aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt3
-rw-r--r--CONTRIBUTORS.txt35
-rw-r--r--COPYING.txt202
-rw-r--r--INSTALL.txt237
-rw-r--r--Makefile.am117
-rw-r--r--README.txt57
-rwxr-xr-xautogen.sh27
-rw-r--r--configure.ac34
-rw-r--r--editors/README.txt5
-rw-r--r--editors/proto.vim83
-rw-r--r--examples/AddPerson.java89
-rw-r--r--examples/ListPeople.java50
-rw-r--r--examples/Makefile56
-rw-r--r--examples/README.txt25
-rw-r--r--examples/add_person.cc92
-rwxr-xr-xexamples/add_person.py58
-rw-r--r--examples/addressbook.proto30
-rw-r--r--examples/list_people.cc65
-rwxr-xr-xexamples/list_people.py38
-rwxr-xr-xgenerate_descriptor_proto.sh35
-rw-r--r--java/README.txt46
-rw-r--r--java/pom.xml107
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessage.java343
-rw-r--r--java/src/main/java/com/google/protobuf/ByteString.java318
-rw-r--r--java/src/main/java/com/google/protobuf/CodedInputStream.java766
-rw-r--r--java/src/main/java/com/google/protobuf/CodedOutputStream.java775
-rw-r--r--java/src/main/java/com/google/protobuf/Descriptors.java1635
-rw-r--r--java/src/main/java/com/google/protobuf/DynamicMessage.java391
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionRegistry.java237
-rw-r--r--java/src/main/java/com/google/protobuf/FieldSet.java662
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessage.java1219
-rw-r--r--java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java77
-rw-r--r--java/src/main/java/com/google/protobuf/Message.java415
-rw-r--r--java/src/main/java/com/google/protobuf/RpcCallback.java27
-rw-r--r--java/src/main/java/com/google/protobuf/RpcChannel.java51
-rw-r--r--java/src/main/java/com/google/protobuf/RpcController.java98
-rw-r--r--java/src/main/java/com/google/protobuf/RpcUtil.java118
-rw-r--r--java/src/main/java/com/google/protobuf/Service.java97
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java1242
-rw-r--r--java/src/main/java/com/google/protobuf/UninitializedMessageException.java146
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSet.java746
-rw-r--r--java/src/main/java/com/google/protobuf/WireFormat.java99
-rw-r--r--java/src/test/java/com/google/protobuf/AbstractMessageTest.java362
-rw-r--r--java/src/test/java/com/google/protobuf/CodedInputStreamTest.java401
-rw-r--r--java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java280
-rw-r--r--java/src/test/java/com/google/protobuf/DescriptorsTest.java313
-rw-r--r--java/src/test/java/com/google/protobuf/DynamicMessageTest.java120
-rw-r--r--java/src/test/java/com/google/protobuf/GeneratedMessageTest.java246
-rw-r--r--java/src/test/java/com/google/protobuf/MessageTest.java299
-rw-r--r--java/src/test/java/com/google/protobuf/ServiceTest.java164
-rw-r--r--java/src/test/java/com/google/protobuf/TestUtil.java2402
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java534
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java315
-rw-r--r--java/src/test/java/com/google/protobuf/WireFormatTest.java226
-rw-r--r--java/src/test/java/com/google/protobuf/multiple_files_test.proto53
-rw-r--r--m4/acx_pthread.m4363
-rw-r--r--m4/stl_hash.m443
-rw-r--r--python/README.txt53
-rwxr-xr-xpython/ez_setup.py277
-rwxr-xr-xpython/google/__init__.py1
-rwxr-xr-xpython/google/protobuf/__init__.py0
-rwxr-xr-xpython/google/protobuf/descriptor.py419
-rwxr-xr-xpython/google/protobuf/internal/__init__.py0
-rwxr-xr-xpython/google/protobuf/internal/decoder.py194
-rwxr-xr-xpython/google/protobuf/internal/decoder_test.py230
-rwxr-xr-xpython/google/protobuf/internal/descriptor_test.py97
-rwxr-xr-xpython/google/protobuf/internal/encoder.py192
-rwxr-xr-xpython/google/protobuf/internal/encoder_test.py211
-rwxr-xr-xpython/google/protobuf/internal/generator_test.py84
-rwxr-xr-xpython/google/protobuf/internal/input_stream.py211
-rwxr-xr-xpython/google/protobuf/internal/input_stream_test.py279
-rwxr-xr-xpython/google/protobuf/internal/message_listener.py55
-rw-r--r--python/google/protobuf/internal/more_extensions.proto44
-rw-r--r--python/google/protobuf/internal/more_messages.proto37
-rwxr-xr-xpython/google/protobuf/internal/output_stream.py112
-rwxr-xr-xpython/google/protobuf/internal/output_stream_test.py162
-rwxr-xr-xpython/google/protobuf/internal/reflection_test.py1300
-rwxr-xr-xpython/google/protobuf/internal/service_reflection_test.py98
-rwxr-xr-xpython/google/protobuf/internal/test_util.py354
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py97
-rwxr-xr-xpython/google/protobuf/internal/wire_format.py222
-rwxr-xr-xpython/google/protobuf/internal/wire_format_test.py232
-rwxr-xr-xpython/google/protobuf/message.py184
-rwxr-xr-xpython/google/protobuf/reflection.py1734
-rwxr-xr-xpython/google/protobuf/service.py194
-rwxr-xr-xpython/google/protobuf/service_reflection.py275
-rwxr-xr-xpython/google/protobuf/text_format.py111
-rwxr-xr-xpython/mox.py1401
-rwxr-xr-xpython/setup.py126
-rwxr-xr-xpython/stubout.py140
-rw-r--r--src/Makefile.am255
-rw-r--r--src/google/protobuf/compiler/code_generator.cc32
-rw-r--r--src/google/protobuf/compiler/code_generator.h98
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc579
-rw-r--r--src/google/protobuf/compiler/command_line_interface.h210
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc964
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc135
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc196
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h81
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc226
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h84
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc104
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.h68
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc83
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h127
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc404
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h82
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc135
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.h58
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc197
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h86
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc1445
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h125
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc229
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h84
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc294
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h84
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc318
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.h104
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc336
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h86
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto87
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc835
-rw-r--r--src/google/protobuf/compiler/importer.cc398
-rw-r--r--src/google/protobuf/compiler/importer.h279
-rw-r--r--src/google/protobuf/compiler/importer_unittest.cc539
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc189
-rw-r--r--src/google/protobuf/compiler/java/java_enum.h70
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc264
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.h84
-rw-r--r--src/google/protobuf/compiler/java/java_extension.cc82
-rw-r--r--src/google/protobuf/compiler/java/java_extension.h58
-rw-r--r--src/google/protobuf/compiler/java/java_field.cc88
-rw-r--r--src/google/protobuf/compiler/java/java_field.h82
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc249
-rw-r--r--src/google/protobuf/compiler/java/java_file.h78
-rw-r--r--src/google/protobuf/compiler/java/java_generator.cc133
-rw-r--r--src/google/protobuf/compiler/java/java_generator.h58
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.cc229
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h102
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc722
-rw-r--r--src/google/protobuf/compiler/java/java_message.h76
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc302
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.h84
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc365
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.h84
-rw-r--r--src/google/protobuf/compiler/java/java_service.cc225
-rw-r--r--src/google/protobuf/compiler/java/java_service.h66
-rw-r--r--src/google/protobuf/compiler/main.cc46
-rw-r--r--src/google/protobuf/compiler/package_info.h50
-rw-r--r--src/google/protobuf/compiler/parser.cc1105
-rw-r--r--src/google/protobuf/compiler/parser.h301
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc1142
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc794
-rw-r--r--src/google/protobuf/compiler/python/python_generator.h129
-rw-r--r--src/google/protobuf/descriptor.cc2838
-rw-r--r--src/google/protobuf/descriptor.h1173
-rw-r--r--src/google/protobuf/descriptor.pb.cc3935
-rw-r--r--src/google/protobuf/descriptor.pb.h2958
-rw-r--r--src/google/protobuf/descriptor.proto286
-rw-r--r--src/google/protobuf/descriptor_database.cc291
-rw-r--r--src/google/protobuf/descriptor_database.h183
-rw-r--r--src/google/protobuf/descriptor_database_unittest.cc601
-rw-r--r--src/google/protobuf/descriptor_unittest.cc2634
-rw-r--r--src/google/protobuf/dynamic_message.cc475
-rw-r--r--src/google/protobuf/dynamic_message.h105
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc117
-rw-r--r--src/google/protobuf/extension_set.cc735
-rw-r--r--src/google/protobuf/extension_set.h555
-rw-r--r--src/google/protobuf/extension_set_unittest.cc195
-rw-r--r--src/google/protobuf/generated_message_reflection.cc665
-rw-r--r--src/google/protobuf/generated_message_reflection.h300
-rw-r--r--src/google/protobuf/generated_message_reflection_unittest.cc251
-rw-r--r--src/google/protobuf/io/coded_stream.cc757
-rw-r--r--src/google/protobuf/io/coded_stream.h592
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc929
-rw-r--r--src/google/protobuf/io/package_info.h40
-rw-r--r--src/google/protobuf/io/printer.cc165
-rw-r--r--src/google/protobuf/io/printer.h109
-rw-r--r--src/google/protobuf/io/printer_unittest.cc210
-rw-r--r--src/google/protobuf/io/tokenizer.cc679
-rw-r--r--src/google/protobuf/io/tokenizer.h276
-rw-r--r--src/google/protobuf/io/tokenizer_unittest.cc706
-rw-r--r--src/google/protobuf/io/zero_copy_stream.cc34
-rw-r--r--src/google/protobuf/io/zero_copy_stream.h224
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.cc793
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.h617
-rw-r--r--src/google/protobuf/io/zero_copy_stream_unittest.cc443
-rw-r--r--src/google/protobuf/message.cc345
-rw-r--r--src/google/protobuf/message.h624
-rw-r--r--src/google/protobuf/message_unittest.cc224
-rw-r--r--src/google/protobuf/package_info.h50
-rw-r--r--src/google/protobuf/reflection_ops.cc241
-rw-r--r--src/google/protobuf/reflection_ops.h74
-rw-r--r--src/google/protobuf/reflection_ops_unittest.cc421
-rw-r--r--src/google/protobuf/repeated_field.cc41
-rw-r--r--src/google/protobuf/repeated_field.h782
-rw-r--r--src/google/protobuf/repeated_field_unittest.cc603
-rw-r--r--src/google/protobuf/service.cc32
-rw-r--r--src/google/protobuf/service.h273
-rw-r--r--src/google/protobuf/stubs/common.cc261
-rw-r--r--src/google/protobuf/stubs/common.h1061
-rw-r--r--src/google/protobuf/stubs/common_unittest.cc319
-rw-r--r--src/google/protobuf/stubs/hash.cc27
-rw-r--r--src/google/protobuf/stubs/hash.h123
-rw-r--r--src/google/protobuf/stubs/map-util.cc28
-rw-r--r--src/google/protobuf/stubs/map-util.h90
-rw-r--r--src/google/protobuf/stubs/stl_util-inl.cc27
-rw-r--r--src/google/protobuf/stubs/stl_util-inl.h107
-rw-r--r--src/google/protobuf/stubs/strutil.cc1121
-rw-r--r--src/google/protobuf/stubs/strutil.h432
-rw-r--r--src/google/protobuf/stubs/strutil_unittest.cc68
-rw-r--r--src/google/protobuf/stubs/substitute.cc120
-rw-r--r--src/google/protobuf/stubs/substitute.h156
-rw-r--r--src/google/protobuf/test_util.cc1912
-rw-r--r--src/google/protobuf/test_util.h118
-rw-r--r--src/google/protobuf/testdata/golden_messagebin0 -> 487 bytes
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_data.txt116
-rw-r--r--src/google/protobuf/testdata/text_format_unittest_extensions_data.txt116
-rw-r--r--src/google/protobuf/testing/file.cc157
-rw-r--r--src/google/protobuf/testing/file.h69
-rw-r--r--src/google/protobuf/testing/googletest.cc189
-rw-r--r--src/google/protobuf/testing/googletest.h81
-rw-r--r--src/google/protobuf/text_format.cc941
-rw-r--r--src/google/protobuf/text_format.h143
-rw-r--r--src/google/protobuf/text_format_unittest.cc697
-rw-r--r--src/google/protobuf/unittest.proto452
-rw-r--r--src/google/protobuf/unittest_embed_optimize_for.proto36
-rw-r--r--src/google/protobuf/unittest_import.proto47
-rw-r--r--src/google/protobuf/unittest_mset.proto58
-rw-r--r--src/google/protobuf/unittest_optimize_for.proto38
-rw-r--r--src/google/protobuf/unknown_field_set.cc112
-rw-r--r--src/google/protobuf/unknown_field_set.h322
-rw-r--r--src/google/protobuf/unknown_field_set_unittest.cc424
-rw-r--r--src/google/protobuf/wire_format.cc801
-rw-r--r--src/google/protobuf/wire_format.h446
-rw-r--r--src/google/protobuf/wire_format_inl.h371
-rw-r--r--src/google/protobuf/wire_format_unittest.cc526
-rw-r--r--src/gtest/CHANGES3
-rw-r--r--src/gtest/CONTRIBUTORS23
-rw-r--r--src/gtest/COPYING28
-rw-r--r--src/gtest/README150
-rwxr-xr-xsrc/gtest/gen_gtest_pred_impl.py733
-rw-r--r--src/gtest/gtest-death-test.cc751
-rw-r--r--src/gtest/gtest-death-test.h205
-rw-r--r--src/gtest/gtest-filepath.cc208
-rw-r--r--src/gtest/gtest-internal-inl.h1118
-rw-r--r--src/gtest/gtest-message.h236
-rw-r--r--src/gtest/gtest-port.cc292
-rw-r--r--src/gtest/gtest-spi.h247
-rw-r--r--src/gtest/gtest.cc3546
-rw-r--r--src/gtest/gtest.h1243
-rw-r--r--src/gtest/gtest_main.cc39
-rw-r--r--src/gtest/gtest_pred_impl.h368
-rw-r--r--src/gtest/gtest_prod.h58
-rw-r--r--src/gtest/internal/gtest-death-test-internal.h201
-rw-r--r--src/gtest/internal/gtest-filepath.h168
-rw-r--r--src/gtest/internal/gtest-internal.h569
-rw-r--r--src/gtest/internal/gtest-port.h596
-rw-r--r--src/gtest/internal/gtest-string.h280
-rw-r--r--vsprojects/config.h21
-rwxr-xr-xvsprojects/convert2008to2005.sh20
-rwxr-xr-xvsprojects/extract_includes.bat36
-rw-r--r--vsprojects/libprotobuf.vcproj408
-rw-r--r--vsprojects/libprotoc.vcproj396
-rw-r--r--vsprojects/protobuf.sln50
-rw-r--r--vsprojects/protoc.vcproj192
-rw-r--r--vsprojects/readme.txt71
-rw-r--r--vsprojects/tests.vcproj569
269 files changed, 96422 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 00000000..853e639a
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,3 @@
+2008-07-07 version 2.0.0:
+
+ * First public release.
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
new file mode 100644
index 00000000..6aeea57a
--- /dev/null
+++ b/CONTRIBUTORS.txt
@@ -0,0 +1,35 @@
+This file contains a list of people who have made large contributions
+to the public version of Protocol Buffers.
+
+Original Protocol Buffers design and implementation:
+ Sanjay Ghemawat <sanjay@google.com>
+ Jeff Dean <jeff@google.com>
+ Daniel Dulitz <daniel@google.com>
+ Craig Silverstein
+ Paul Haahr <haahr@google.com>
+ Corey Anderson <corin@google.com>
+ (and many others)
+
+Proto2 C++ and Java primary author:
+ Kenton Varda <kenton@google.com>
+
+Proto2 Python primary authors:
+ Will Robinson <robinson@google.com>
+ Petar Petrov <petar@google.com>
+
+Large code contributions:
+ Joseph Schorr <jschorr@google.com>
+ Wenbo Zhu <wenboz@google.com>
+
+Large quantity of code reviews:
+ Scott Bruce <sbruce@google.com>
+ Frank Yellin
+ Neal Norwitz <nnorwitz@google.com>
+ Jeffrey Yasskin <jyasskin@google.com>
+ Ambrose Feinstein <ambrose@google.com>
+
+Documentation:
+ Lisa Carey <lcarey@google.com>
+
+Maven packaging:
+ Gregory Kick <gak@google.com>
diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/COPYING.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 00000000..ce3b0949
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,237 @@
+This file contains detailed but generic information on building and
+installing the C++ part of this project. For shorter instructions,
+as well as instructions for compiling and installing the Java or
+Python parts, see README.
+
+======================================================================
+
+Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..4e2f6515
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,117 @@
+## Process this file with automake to produce Makefile.in
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src
+
+EXTRA_DIST = \
+ autogen.sh \
+ generate_descriptor_proto.sh \
+ README.txt \
+ INSTALL.txt \
+ COPYING.txt \
+ CONTRIBUTORS.txt \
+ CHANGES.txt \
+ editors/README.txt \
+ editors/proto.vim \
+ vsprojects/config.h \
+ vsprojects/extract_includes.bat \
+ vsprojects/libprotobuf.vcproj \
+ vsprojects/libprotoc.vcproj \
+ vsprojects/protobuf.sln \
+ vsprojects/protoc.vcproj \
+ vsprojects/readme.txt \
+ vsprojects/tests.vcproj \
+ vsprojects/convert2008to2005.sh \
+ examples/README.txt \
+ examples/Makefile \
+ examples/addressbook.proto \
+ examples/add_person.cc \
+ examples/list_people.cc \
+ examples/AddPerson.java \
+ examples/ListPeople.java \
+ examples/add_person.py \
+ examples/list_people.py \
+ java/src/main/java/com/google/protobuf/AbstractMessage.java \
+ java/src/main/java/com/google/protobuf/ByteString.java \
+ java/src/main/java/com/google/protobuf/CodedInputStream.java \
+ java/src/main/java/com/google/protobuf/CodedOutputStream.java \
+ java/src/main/java/com/google/protobuf/Descriptors.java \
+ java/src/main/java/com/google/protobuf/DynamicMessage.java \
+ java/src/main/java/com/google/protobuf/ExtensionRegistry.java \
+ java/src/main/java/com/google/protobuf/FieldSet.java \
+ java/src/main/java/com/google/protobuf/GeneratedMessage.java \
+ java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
+ java/src/main/java/com/google/protobuf/Message.java \
+ java/src/main/java/com/google/protobuf/RpcCallback.java \
+ java/src/main/java/com/google/protobuf/RpcChannel.java \
+ java/src/main/java/com/google/protobuf/RpcController.java \
+ java/src/main/java/com/google/protobuf/RpcUtil.java \
+ java/src/main/java/com/google/protobuf/Service.java \
+ java/src/main/java/com/google/protobuf/TextFormat.java \
+ java/src/main/java/com/google/protobuf/UninitializedMessageException.java \
+ java/src/main/java/com/google/protobuf/UnknownFieldSet.java \
+ java/src/main/java/com/google/protobuf/WireFormat.java \
+ java/src/test/java/com/google/protobuf/AbstractMessageTest.java \
+ java/src/test/java/com/google/protobuf/CodedInputStreamTest.java \
+ java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java \
+ java/src/test/java/com/google/protobuf/DescriptorsTest.java \
+ java/src/test/java/com/google/protobuf/DynamicMessageTest.java \
+ java/src/test/java/com/google/protobuf/GeneratedMessageTest.java \
+ java/src/test/java/com/google/protobuf/MessageTest.java \
+ java/src/test/java/com/google/protobuf/ServiceTest.java \
+ java/src/test/java/com/google/protobuf/TestUtil.java \
+ java/src/test/java/com/google/protobuf/TextFormatTest.java \
+ java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java \
+ java/src/test/java/com/google/protobuf/WireFormatTest.java \
+ java/src/test/java/com/google/protobuf/multiple_files_test.proto \
+ java/pom.xml \
+ java/README.txt \
+ python/google/protobuf/internal/generator_test.py \
+ python/google/protobuf/internal/decoder.py \
+ python/google/protobuf/internal/decoder_test.py \
+ python/google/protobuf/internal/descriptor_test.py \
+ python/google/protobuf/internal/encoder.py \
+ python/google/protobuf/internal/encoder_test.py \
+ python/google/protobuf/internal/input_stream.py \
+ python/google/protobuf/internal/input_stream_test.py \
+ python/google/protobuf/internal/message_listener.py \
+ python/google/protobuf/internal/more_extensions.proto \
+ python/google/protobuf/internal/more_messages.proto \
+ python/google/protobuf/internal/output_stream.py \
+ python/google/protobuf/internal/output_stream_test.py \
+ python/google/protobuf/internal/reflection_test.py \
+ python/google/protobuf/internal/service_reflection_test.py \
+ python/google/protobuf/internal/test_util.py \
+ python/google/protobuf/internal/text_format_test.py \
+ python/google/protobuf/internal/wire_format.py \
+ python/google/protobuf/internal/wire_format_test.py \
+ python/google/protobuf/internal/__init__.py \
+ python/google/protobuf/descriptor.py \
+ python/google/protobuf/message.py \
+ python/google/protobuf/reflection.py \
+ python/google/protobuf/service.py \
+ python/google/protobuf/service_reflection.py \
+ python/google/protobuf/text_format.py \
+ python/google/protobuf/__init__.py \
+ python/google/__init__.py \
+ python/ez_setup.py \
+ python/setup.py \
+ python/mox.py \
+ python/stubout.py \
+ python/README.txt
+
+# Deletes all the files generated by autogen.sh.
+MAINTAINERCLEANFILES = \
+ aclocal.m4 \
+ config.guess \
+ config.sub \
+ configure \
+ depcomp \
+ install-sh \
+ ltmain.sh \
+ Makefile.in \
+ missing \
+ mkinstalldirs \
+ config.h.in \
+ stamp.h.in
diff --git a/README.txt b/README.txt
new file mode 100644
index 00000000..75a429af
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,57 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+http://code.google.com/apis/protocolbuffers/
+
+BETA WARNING
+============
+
+This package is a beta. This means that API may change in an
+incompatible way in the future. It's unlikely that any big changes
+will be made, but we can make no promises. Expect a non-beta release
+sometime in August 2008.
+
+C++ Installation
+================
+
+To build and install the C++ Protocol Buffer runtime and the Protocol
+Buffer compiler (protoc) execute the following:
+
+ $ ./configure
+ $ make
+ $ make check
+ $ make install
+
+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.
+
+"make install" may require superuser privileges.
+
+For advanced usage information on configure and make, see INSTALL.
+
+** 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.
+
+Java and Python Installation
+============================
+
+The Java and Python runtime libraries for Protocol Buffers are located
+in the java and python directories. See the README file in each
+directory for more information on how to compile and install them.
+Note that both of them require you to first install the Protocol
+Buffer compiler (protoc), which is part of the C++ package.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ http://code.google.com/apis/protocolbuffers/
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 00000000..34a4d2e3
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Run this script to generate the configure script and other files that will
+# be included in the distribution. These files are not checked in because they
+# are automatically generated.
+
+# Check that we're being run from the right directory.
+if test ! -e src/google/protobuf/stubs/common.h; then
+ cat >&2 << __EOF__
+Could not find source code. Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+ exit 1
+fi
+
+set -ex
+
+rm -rf autom4te.cache
+
+aclocal-1.9 --force -I m4
+libtoolize -c -f
+autoheader -f -W all
+automake-1.9 --foreign -a -c -f -W all
+autoconf -f -W all,no-obsolete
+
+rm -rf autom4te.cache config.h.in~
+exit 0
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 00000000..6dca1633
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,34 @@
+## Process this file with autoconf to produce configure.
+## In general, the safest way to proceed is to run ./autogen.sh
+
+AC_PREREQ(2.59)
+
+# Note: If you change the version, you must also update it in:
+# * java/pom.xml
+# * python/setup.py
+# * src/google/protobuf/stubs/common.h
+AC_INIT(protobuf, 2.0.1-SNAPSHOT, protobuf@googlegroups.com)
+
+AC_CONFIG_SRCDIR(src/google/protobuf/message.cc)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h stdlib.h unistd.h])
+
+# Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_STRTOD
+AC_CHECK_FUNCS([ftruncate memset mkdir strchr strerror strtol])
+
+ACX_PTHREAD
+AC_CXX_STL_HASH
+
+AC_OUTPUT( Makefile src/Makefile )
diff --git a/editors/README.txt b/editors/README.txt
new file mode 100644
index 00000000..3e9fc79e
--- /dev/null
+++ b/editors/README.txt
@@ -0,0 +1,5 @@
+This directory contains syntax highlighting and configuration files for editors
+to properly display Protocol Buffer files.
+
+See each file's header comment for directions on how to use it with the
+appropriate editor.
diff --git a/editors/proto.vim b/editors/proto.vim
new file mode 100644
index 00000000..ea010480
--- /dev/null
+++ b/editors/proto.vim
@@ -0,0 +1,83 @@
+" Protocol Buffers - Google's data interchange format
+" 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 is the Vim syntax file for Google Protocol Buffers.
+"
+" Usage:
+"
+" 1. cp proto.vim ~/.vim/syntax/
+" 2. Add the following to ~/.vimrc:
+"
+" augroup filetype
+" au! BufRead,BufNewFile *.proto setfiletype proto
+" augroup end
+
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn case match
+
+syn keyword pbSyntax syntax import option
+syn keyword pbStructure package message group
+syn keyword pbRepeat optional required repeated
+syn keyword pbDefault default
+syn keyword pbExtend extend extensions to max
+syn keyword pbRPC service rpc returns
+
+syn keyword pbType int32 int64 uint32 uint64 sint32 sint64
+syn keyword pbType fixed32 fixed64 sfixed32 sfixed64
+syn keyword pbType float double bool string bytes
+syn keyword pbTypedef enum
+syn keyword pbBool true false
+
+syn match pbInt /-\?\<\d\+\>/
+syn match pbInt /\<0[xX]\x+\>/
+syn match pbFloat /\<-\?\d*\(\.\d*\)\?/
+" TODO: .proto also supports C-style block comments;
+" see /usr/share/vim/vim70/syntax/c.vim for how it's done.
+syn match pbComment /\/\/.*$/
+syn region pbString start=/"/ skip=/\\"/ end=/"/
+syn region pbString start=/'/ skip=/\\'/ end=/'/
+
+if version >= 508 || !exists("did_proto_syn_inits")
+ if version < 508
+ let did_proto_syn_inits = 1
+ command -nargs=+ HiLink hi link <args>
+ else
+ command -nargs=+ HiLink hi def link <args>
+ endif
+
+ HiLink pbSyntax Include
+ HiLink pbStructure Structure
+ HiLink pbRepeat Repeat
+ HiLink pbDefault Keyword
+ HiLink pbExtend Keyword
+ HiLink pbRPC Keyword
+ HiLink pbType Type
+ HiLink pbTypedef Typedef
+ HiLink pbBool Boolean
+
+ HiLink pbInt Number
+ HiLink pbFloat Float
+ HiLink pbComment Comment
+ HiLink pbString String
+
+ delcommand HiLink
+endif
+
+let b:current_syntax = "proto"
diff --git a/examples/AddPerson.java b/examples/AddPerson.java
new file mode 100644
index 00000000..4917684b
--- /dev/null
+++ b/examples/AddPerson.java
@@ -0,0 +1,89 @@
+// See README.txt for information and build instructions.
+
+import com.example.tutorial.AddressBookProtos.AddressBook;
+import com.example.tutorial.AddressBookProtos.Person;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+class AddPerson {
+ // This function fills in a Person message based on user input.
+ static Person PromptForAddress(BufferedReader stdin,
+ PrintStream stdout) throws IOException {
+ Person.Builder person = Person.newBuilder();
+
+ stdout.print("Enter person ID: ");
+ person.setId(Integer.valueOf(stdin.readLine()));
+
+ stdout.print("Enter name: ");
+ person.setName(stdin.readLine());
+
+ stdout.print("Enter email address (blank for none): ");
+ String email = stdin.readLine();
+ if (email.length() > 0) {
+ person.setEmail(email);
+ }
+
+ while (true) {
+ stdout.print("Enter a phone number (or leave blank to finish): ");
+ String number = stdin.readLine();
+ if (number.length() == 0) {
+ break;
+ }
+
+ Person.PhoneNumber.Builder phoneNumber =
+ Person.PhoneNumber.newBuilder().setNumber(number);
+
+ stdout.print("Is this a mobile, home, or work phone? ");
+ String type = stdin.readLine();
+ if (type.equals("mobile")) {
+ phoneNumber.setType(Person.PhoneType.MOBILE);
+ } else if (type.equals("home")) {
+ phoneNumber.setType(Person.PhoneType.HOME);
+ } else if (type.equals("work")) {
+ phoneNumber.setType(Person.PhoneType.WORK);
+ } else {
+ stdout.println("Unknown phone type. Using default.");
+ }
+
+ person.addPhone(phoneNumber);
+ }
+
+ return person.build();
+ }
+
+ // Main function: Reads the entire address book from a file,
+ // adds one person based on user input, then writes it back out to the same
+ // file.
+ public static void main(String[] args) throws Exception {
+ if (args.length != 1) {
+ System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE");
+ System.exit(-1);
+ }
+
+ AddressBook.Builder addressBook = AddressBook.newBuilder();
+
+ // Read the existing address book.
+ try {
+ FileInputStream input = new FileInputStream(args[0]);
+ addressBook.mergeFrom(input);
+ input.close();
+ } catch (FileNotFoundException e) {
+ System.out.println(args[0] + ": File not found. Creating a new file.");
+ }
+
+ // Add an address.
+ addressBook.addPerson(
+ PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
+ System.out));
+
+ // Write the new address book back to disk.
+ FileOutputStream output = new FileOutputStream(args[0]);
+ addressBook.build().writeTo(output);
+ output.close();
+ }
+}
diff --git a/examples/ListPeople.java b/examples/ListPeople.java
new file mode 100644
index 00000000..b2f153af
--- /dev/null
+++ b/examples/ListPeople.java
@@ -0,0 +1,50 @@
+// See README.txt for information and build instructions.
+
+import com.example.tutorial.AddressBookProtos.AddressBook;
+import com.example.tutorial.AddressBookProtos.Person;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+class ListPeople {
+ // Iterates though all people in the AddressBook and prints info about them.
+ static void Print(AddressBook addressBook) {
+ for (Person person: addressBook.getPersonList()) {
+ System.out.println("Person ID: " + person.getId());
+ System.out.println(" Name: " + person.getName());
+ if (person.hasEmail()) {
+ System.out.println(" E-mail address: " + person.getEmail());
+ }
+
+ for (Person.PhoneNumber phoneNumber : person.getPhoneList()) {
+ switch (phoneNumber.getType()) {
+ case MOBILE:
+ System.out.print(" Mobile phone #: ");
+ break;
+ case HOME:
+ System.out.print(" Home phone #: ");
+ break;
+ case WORK:
+ System.out.print(" Work phone #: ");
+ break;
+ }
+ System.out.println(phoneNumber.getNumber());
+ }
+ }
+ }
+
+ // Main function: Reads the entire address book from a file and prints all
+ // the information inside.
+ public static void main(String[] args) throws Exception {
+ if (args.length != 1) {
+ System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE");
+ System.exit(-1);
+ }
+
+ // Read the existing address book.
+ AddressBook addressBook =
+ AddressBook.parseFrom(new FileInputStream(args[0]));
+
+ Print(addressBook);
+ }
+}
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 00000000..999ee94a
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,56 @@
+# See README.txt.
+
+.PHONY: all cpp java python clean
+
+all: cpp java python
+
+cpp: add_person_cpp list_people_cpp
+java: add_person_java list_people_java
+python: add_person_python list_people_python
+
+clean:
+ rm -f add_person_cpp list_people_cpp add_person_java list_people_java add_person_python list_people_python
+ rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
+ rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
+ rm -f *.pyc
+ rmdir com/example/tutorial 2>/dev/null || true
+ rmdir com/example 2>/dev/null || true
+ rmdir com 2>/dev/null || true
+
+protoc_middleman: addressbook.proto
+ protoc --cpp_out=. --java_out=. --python_out=. addressbook.proto
+ @touch protoc_middleman
+
+add_person_cpp: add_person.cc protoc_middleman
+ c++ add_person.cc addressbook.pb.cc -lprotobuf -o add_person_cpp
+
+list_people_cpp: list_people.cc protoc_middleman
+ c++ list_people.cc addressbook.pb.cc -lprotobuf -o list_people_cpp
+
+javac_middleman: AddPerson.java ListPeople.java protoc_middleman
+ javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
+ @touch javac_middleman
+
+add_person_java: javac_middleman
+ @echo "Writing shortcut script add_person_java..."
+ @echo '#! /bin/sh' > add_person_java
+ @echo 'java -classpath .:$$CLASSPATH AddPerson "$$@"' >> add_person_java
+ @chmod +x add_person_java
+
+list_people_java: javac_middleman
+ @echo "Writing shortcut script list_people_java..."
+ @echo '#! /bin/sh' > list_people_java
+ @echo 'java -classpath .:$$CLASSPATH ListPeople "$$@"' >> list_people_java
+ @chmod +x list_people_java
+
+add_person_python: add_person.py protoc_middleman
+ @echo "Writing shortcut script add_person_python..."
+ @echo '#! /bin/sh' > add_person_python
+ @echo './add_person.py "$$@"' >> add_person_python
+ @chmod +x add_person_python
+
+list_people_python: list_people.py protoc_middleman
+ @echo "Writing shortcut script list_people_python..."
+ @echo '#! /bin/sh' > list_people_python
+ @echo './list_people.py "$$@"' >> list_people_python
+ @chmod +x list_people_python
diff --git a/examples/README.txt b/examples/README.txt
new file mode 100644
index 00000000..b0d1a0c2
--- /dev/null
+++ b/examples/README.txt
@@ -0,0 +1,25 @@
+This directory contains example code that uses Protocol Buffers to manage an
+address book. Two programs are provided, each with three different
+implementations, one written in each of C++, Java, and Python. The add_person
+example adds a new person to an address book, prompting the user to input
+the person's information. The list_people example lists people already in the
+address book. The examples use the exact same format in all three languages,
+so you can, for example, use add_person_java to create an address book and then
+use list_people_python to read it.
+
+You must install the protobuf package before you can build these.
+
+To build all the examples (on a unix-like system), simply run "make". This
+creates the following executable files in the current directory:
+ add_person_cpp list_people_cpp
+ add_person_java list_people_java
+ add_person_python list_people_python
+
+If you only want to compile examples in one language, use "make cpp",
+"make java", or "make python".
+
+All of these programs simply take an address book file as their parameter.
+The add_person programs will create the file if it doesn't already exist.
+
+These examples are part of the Protocol Buffers tutorial, located at:
+ http://code.google.com/apis/protocolbuffers/docs/tutorials.html
diff --git a/examples/add_person.cc b/examples/add_person.cc
new file mode 100644
index 00000000..2aca216b
--- /dev/null
+++ b/examples/add_person.cc
@@ -0,0 +1,92 @@
+// See README.txt for information and build instructions.
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include "addressbook.pb.h"
+using namespace std;
+
+// This function fills in a Person message based on user input.
+void PromptForAddress(tutorial::Person* person) {
+ cout << "Enter person ID number: ";
+ int id;
+ cin >> id;
+ person->set_id(id);
+ cin.ignore(256, '\n');
+
+ cout << "Enter name: ";
+ getline(cin, *person->mutable_name());
+
+ cout << "Enter email address (blank for none): ";
+ string email;
+ getline(cin, email);
+ if (!email.empty()) {
+ person->set_email(email);
+ }
+
+ while (true) {
+ cout << "Enter a phone number (or leave blank to finish): ";
+ string number;
+ getline(cin, number);
+ if (number.empty()) {
+ break;
+ }
+
+ tutorial::Person::PhoneNumber* phone_number = person->add_phone();
+ phone_number->set_number(number);
+
+ cout << "Is this a mobile, home, or work phone? ";
+ string type;
+ getline(cin, type);
+ if (type == "mobile") {
+ phone_number->set_type(tutorial::Person::MOBILE);
+ } else if (type == "home") {
+ phone_number->set_type(tutorial::Person::HOME);
+ } else if (type == "work") {
+ phone_number->set_type(tutorial::Person::WORK);
+ } else {
+ cout << "Unknown phone type. Using default." << endl;
+ }
+ }
+}
+
+// Main function: Reads the entire address book from a file,
+// adds one person based on user input, then writes it back out to the same
+// file.
+int main(int argc, char* argv[]) {
+ // Verify that the version of the library that we linked against is
+ // compatible with the version of the headers we compiled against.
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ if (argc != 2) {
+ cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
+ return -1;
+ }
+
+ tutorial::AddressBook address_book;
+
+ {
+ // Read the existing address book.
+ fstream input(argv[1], ios::in | ios::binary);
+ if (!input) {
+ cout << argv[1] << ": File not found. Creating a new file." << endl;
+ } else if (!address_book.ParseFromIstream(&input)) {
+ cerr << "Failed to parse address book." << endl;
+ return -1;
+ }
+ }
+
+ // Add an address.
+ PromptForAddress(address_book.add_person());
+
+ {
+ // Write the new address book back to disk.
+ fstream output(argv[1], ios::out | ios::trunc | ios::binary);
+ if (!address_book.SerializeToOstream(&output)) {
+ cerr << "Failed to write address book." << endl;
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/add_person.py b/examples/add_person.py
new file mode 100755
index 00000000..78e56966
--- /dev/null
+++ b/examples/add_person.py
@@ -0,0 +1,58 @@
+#! /usr/bin/python
+
+# See README.txt for information and build instructions.
+
+import addressbook_pb2
+import sys
+
+# This function fills in a Person message based on user input.
+def PromptForAddress(person):
+ person.id = int(raw_input("Enter person ID number: "))
+ person.name = raw_input("Enter name: ")
+
+ email = raw_input("Enter email address (blank for none): ")
+ if email != "":
+ person.email = email
+
+ while True:
+ number = raw_input("Enter a phone number (or leave blank to finish): ")
+ if number == "":
+ break
+
+ phone_number = person.phone.add()
+ phone_number.number = number
+
+ type = raw_input("Is this a mobile, home, or work phone? ")
+ if type == "mobile":
+ phone_number.type = addressbook_pb2.Person.MOBILE
+ elif type == "home":
+ phone_number.type = addressbook_pb2.Person.HOME
+ elif type == "work":
+ phone_number.type = addressbook_pb2.Person.WORK
+ else:
+ print "Unknown phone type; leaving as default value."
+
+# Main procedure: Reads the entire address book from a file,
+# adds one person based on user input, then writes it back out to the same
+# file.
+if len(sys.argv) != 2:
+ print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
+ sys.exit(-1)
+
+address_book = addressbook_pb2.AddressBook()
+
+# Read the existing address book.
+try:
+ f = open(sys.argv[1], "rb")
+ address_book.ParseFromString(f.read())
+ f.close()
+except IOError:
+ print sys.argv[1] + ": File not found. Creating a new file."
+
+# Add an address.
+PromptForAddress(address_book.person.add())
+
+# Write the new address book back to disk.
+f = open(sys.argv[1], "wb")
+f.write(address_book.SerializeToString())
+f.close()
diff --git a/examples/addressbook.proto b/examples/addressbook.proto
new file mode 100644
index 00000000..b14829e9
--- /dev/null
+++ b/examples/addressbook.proto
@@ -0,0 +1,30 @@
+// See README.txt for information and build instructions.
+
+package tutorial;
+
+option java_package = "com.example.tutorial";
+option java_outer_classname = "AddressBookProtos";
+
+message Person {
+ required string name = 1;
+ required int32 id = 2; // Unique ID number for this person.
+ optional string email = 3;
+
+ enum PhoneType {
+ MOBILE = 0;
+ HOME = 1;
+ WORK = 2;
+ }
+
+ message PhoneNumber {
+ required string number = 1;
+ optional PhoneType type = 2 [default = HOME];
+ }
+
+ repeated PhoneNumber phone = 4;
+}
+
+// Our address book file is just one of these.
+message AddressBook {
+ repeated Person person = 1;
+}
diff --git a/examples/list_people.cc b/examples/list_people.cc
new file mode 100644
index 00000000..bd9a583f
--- /dev/null
+++ b/examples/list_people.cc
@@ -0,0 +1,65 @@
+// See README.txt for information and build instructions.
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include "addressbook.pb.h"
+using namespace std;
+
+// Iterates though all people in the AddressBook and prints info about them.
+void ListPeople(const tutorial::AddressBook& address_book) {
+ for (int i = 0; i < address_book.person_size(); i++) {
+ const tutorial::Person& person = address_book.person(i);
+
+ cout << "Person ID: " << person.id() << endl;
+ cout << " Name: " << person.name() << endl;
+ if (person.has_email()) {
+ cout << " E-mail address: " << person.email() << endl;
+ }
+
+ for (int j = 0; j < person.phone_size(); j++) {
+ const tutorial::Person::PhoneNumber& phone_number = person.phone(j);
+
+ switch (phone_number.type()) {
+ case tutorial::Person::MOBILE:
+ cout << " Mobile phone #: ";
+ break;
+ case tutorial::Person::HOME:
+ cout << " Home phone #: ";
+ break;
+ case tutorial::Person::WORK:
+ cout << " Work phone #: ";
+ break;
+ }
+ cout << phone_number.number() << endl;
+ }
+ }
+}
+
+// Main function: Reads the entire address book from a file and prints all
+// the information inside.
+int main(int argc, char* argv[]) {
+ // Verify that the version of the library that we linked against is
+ // compatible with the version of the headers we compiled against.
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ if (argc != 2) {
+ cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
+ return -1;
+ }
+
+ tutorial::AddressBook address_book;
+
+ {
+ // Read the existing address book.
+ fstream input(argv[1], ios::in | ios::binary);
+ if (!address_book.ParseFromIstream(&input)) {
+ cerr << "Failed to parse address book." << endl;
+ return -1;
+ }
+ }
+
+ ListPeople(address_book);
+
+ return 0;
+}
diff --git a/examples/list_people.py b/examples/list_people.py
new file mode 100755
index 00000000..76f4bf1e
--- /dev/null
+++ b/examples/list_people.py
@@ -0,0 +1,38 @@
+#! /usr/bin/python
+
+# See README.txt for information and build instructions.
+
+import addressbook_pb2
+import sys
+
+# Iterates though all people in the AddressBook and prints info about them.
+def ListPeople(address_book):
+ for person in address_book.person:
+ print "Person ID:", person.id
+ print " Name:", person.name
+ if person.HasField('email'):
+ print " E-mail address:", person.email
+
+ for phone_number in person.phone:
+ if phone_number.type == addressbook_pb2.Person.MOBILE:
+ print " Mobile phone #: ",
+ elif phone_number.type == addressbook_pb2.Person.HOME:
+ print " Home phone #: ",
+ elif phone_number.type == addressbook_pb2.Person.WORK:
+ print " Work phone #: ",
+ print phone_number.number
+
+# Main procedure: Reads the entire address book from a file and prints all
+# the information inside.
+if len(sys.argv) != 2:
+ print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
+ sys.exit(-1)
+
+address_book = addressbook_pb2.AddressBook()
+
+# Read the existing address book.
+f = open(sys.argv[1], "rb")
+address_book.ParseFromString(f.read())
+f.close()
+
+ListPeople(address_book)
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
new file mode 100755
index 00000000..53e88e67
--- /dev/null
+++ b/generate_descriptor_proto.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Run this script to regenerate descriptor.pb.{h,cc} after the protocol
+# compiler changes. Since these files are compiled into the protocol compiler
+# itself, they cannot be generated automatically by a make rule. "make check"
+# will fail if these files do not match what the protocol compiler would
+# generate.
+
+# Note that this will always need to be run once after running
+# extract_from_google3.sh. That script initially copies descriptor.pb.{h,cc}
+# over from the google3 code and fixes it up to compile outside of google3, but
+# it cannot fix the encoded descriptor embedded in descriptor.pb.cc. So, once
+# the protocol compiler has been built with the slightly-broken
+# descriptor.pb.cc, the files must be regenerated and the compiler must be
+# built again.
+
+if test ! -e src/google/protobuf/stubs/common.h; then
+ cat >&2 << __EOF__
+Could not find source code. Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+ exit 1
+fi
+
+if test ! -e src/Makefile; then
+ cat >&2 << __EOF__
+Could not find src/Makefile. You must run ./configure (and perhaps
+./autogen.sh) first.
+__EOF__
+ exit 1
+fi
+
+pushd src
+make protoc && ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto
+popd
diff --git a/java/README.txt b/java/README.txt
new file mode 100644
index 00000000..3bb69236
--- /dev/null
+++ b/java/README.txt
@@ -0,0 +1,46 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers runtime library.
+
+Installation
+============
+
+1) Install Apache Maven if you don't have it:
+
+ http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ You will need to place the protoc executable in ../src. (If you
+ built it yourself, it should already be there.)
+
+3) Run the tests:
+
+ $ mvn test
+
+ If some tests fail, this library may not work correctly on your
+ system. Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+ $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+ .jar file to use:
+
+ $ mvn package
+
+ The .jar will be placed in the "target" directory.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ http://code.google.com/apis/protocolbuffers/
diff --git a/java/pom.xml b/java/pom.xml
new file mode 100644
index 00000000..76b3235c
--- /dev/null
+++ b/java/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <!-- This is commented until the parent can be deployed to a repository. -->
+ <!--
+ <parent>
+ <groupId>com</groupId>
+ <artifactId>google</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ -->
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>2.0.1-SNAPSHOT</version>
+ <name>Protocol Buffer Java API</name>
+ <packaging>jar</packaging>
+ <inceptionYear>2008</inceptionYear>
+ <url>http://code.google.com/p/protobuf</url>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-sources</id>
+ <phase>generate-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--java_out=target/generated-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="../src/google/protobuf/descriptor.proto" />
+ </exec>
+ </tasks>
+ <sourceRoot>target/generated-sources</sourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>generate-test-sources</id>
+ <phase>generate-test-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-test-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--java_out=target/generated-test-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="--proto_path=src/test/java" />
+ <arg value="../src/google/protobuf/unittest.proto" />
+ <arg value="../src/google/protobuf/unittest_import.proto" />
+ <arg value="../src/google/protobuf/unittest_mset.proto" />
+ <arg value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
+ <arg
+ value="../src/google/protobuf/unittest_optimize_for.proto" />
+ </exec>
+ </tasks>
+ <testSourceRoot>target/generated-test-sources</testSourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
new file mode 100644
index 00000000..f4145190
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -0,0 +1,343 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A partial implementation of the {@link Message} interface which implements
+ * as many methods of that interface as possible in terms of other methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessage implements Message {
+ @SuppressWarnings("unchecked")
+ public boolean isInitialized() {
+ // Check that all required fields are present.
+ for (FieldDescriptor field : getDescriptorForType().getFields()) {
+ if (field.isRequired()) {
+ if (!hasField(field)) {
+ return false;
+ }
+ }
+ }
+
+ // Check that embedded messages are initialized.
+ for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ for (Message element : (List<Message>) entry.getValue()) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!((Message) entry.getValue()).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public final String toString() {
+ return TextFormat.printToString(this);
+ }
+
+ public void writeTo(CodedOutputStream output) throws IOException {
+ for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ for (Object element : (List) entry.getValue()) {
+ output.writeField(field.getType(), field.getNumber(), element);
+ }
+ } else {
+ output.writeField(field.getType(), field.getNumber(), entry.getValue());
+ }
+ }
+
+ UnknownFieldSet unknownFields = getUnknownFields();
+ if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
+ unknownFields.writeAsMessageSetTo(output);
+ } else {
+ unknownFields.writeTo(output);
+ }
+ }
+
+ public ByteString toByteString() {
+ try {
+ ByteString.CodedBuilder out =
+ ByteString.newCodedBuilder(getSerializedSize());
+ writeTo(out.getCodedOutput());
+ return out.build();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public byte[] toByteArray() {
+ try {
+ byte[] result = new byte[getSerializedSize()];
+ CodedOutputStream output = CodedOutputStream.newInstance(result);
+ writeTo(output);
+ output.checkNoSpaceLeft();
+ return result;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a byte array threw an IOException " +
+ "(should never happen).", e);
+ }
+ }
+
+ public void writeTo(OutputStream output) throws IOException {
+ CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ private int memoizedSize = -1;
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ for (Object element : (List) entry.getValue()) {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), element);
+ }
+ } else {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), entry.getValue());
+ }
+ }
+
+ UnknownFieldSet unknownFields = getUnknownFields();
+ if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
+ size += unknownFields.getSerializedSizeAsMessageSet();
+ } else {
+ size += unknownFields.getSerializedSize();
+ }
+
+ memoizedSize = size;
+ return size;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof Message)) {
+ return false;
+ }
+ Message otherMessage = (Message) other;
+ if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
+ return false;
+ }
+ return getAllFields().equals(otherMessage.getAllFields());
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 41;
+ hash = (19 * hash) + getDescriptorForType().hashCode();
+ hash = (53 * hash) + getAllFields().hashCode();
+ return hash;
+ }
+
+ // =================================================================
+
+ /**
+ * A partial implementation of the {@link Message.Builder} interface which
+ * implements as many methods of that interface as possible in terms of
+ * other methods.
+ */
+ @SuppressWarnings("unchecked")
+ public static abstract class Builder<BuilderType extends Builder>
+ implements Message.Builder {
+ // The compiler produces an error if this is not declared explicitly.
+ public abstract BuilderType clone();
+
+ public BuilderType clear() {
+ for (Map.Entry<FieldDescriptor, Object> entry :
+ getAllFields().entrySet()) {
+ clearField(entry.getKey());
+ }
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(Message other) {
+ if (other.getDescriptorForType() != getDescriptorForType()) {
+ throw new IllegalArgumentException(
+ "mergeFrom(Message) can only merge messages of the same type.");
+ }
+
+ // Note: We don't attempt to verify that other's fields have valid
+ // types. Doing so would be a losing battle. We'd have to verify
+ // all sub-messages as well, and we'd have to make copies of all of
+ // them to insure that they don't change after verification (since
+ // the Message interface itself cannot enforce immutability of
+ // implementations).
+ // TODO(kenton): Provide a function somewhere called makeDeepCopy()
+ // which allows people to make secure deep copies of messages.
+
+ for (Map.Entry<FieldDescriptor, Object> entry :
+ other.getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ for (Object element : (List)entry.getValue()) {
+ addRepeatedField(field, element);
+ }
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ Message existingValue = (Message)getField(field);
+ if (existingValue == existingValue.getDefaultInstanceForType()) {
+ setField(field, entry.getValue());
+ } else {
+ setField(field,
+ existingValue.newBuilderForType()
+ .mergeFrom(existingValue)
+ .mergeFrom((Message)entry.getValue())
+ .build());
+ }
+ } else {
+ setField(field, entry.getValue());
+ }
+ }
+
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(CodedInputStream input) throws IOException {
+ return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
+ }
+
+ public BuilderType mergeFrom(CodedInputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ UnknownFieldSet.Builder unknownFields =
+ UnknownFieldSet.newBuilder(getUnknownFields());
+ FieldSet.mergeFrom(input, unknownFields, extensionRegistry, this);
+ setUnknownFields(unknownFields.build());
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) {
+ setUnknownFields(
+ UnknownFieldSet.newBuilder(getUnknownFields())
+ .mergeFrom(unknownFields)
+ .build());
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(ByteString data)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = data.newCodedInput();
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(ByteString data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = data.newCodedInput();
+ mergeFrom(input, extensionRegistry);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(byte[] data)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(
+ byte[] data, ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ mergeFrom(input, extensionRegistry);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(InputStream input) throws IOException {
+ CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput);
+ codedInput.checkLastTagWas(0);
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(InputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput, extensionRegistry);
+ codedInput.checkLastTagWas(0);
+ return (BuilderType) this;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java
new file mode 100644
index 00000000..4da03eca
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ByteString.java
@@ -0,0 +1,318 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Immutable array of bytes.
+ *
+ * @author crazybob@google.com Bob Lee
+ * @author kenton@google.com Kenton Varda
+ */
+public final class ByteString {
+ private final byte[] bytes;
+
+ private ByteString(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ /**
+ * Gets the byte at the given index.
+ *
+ * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+ */
+ public byte byteAt(int index) {
+ return bytes[index];
+ }
+
+ /**
+ * Gets the number of bytes.
+ */
+ public int size() {
+ return this.bytes.length;
+ }
+
+ /**
+ * Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
+ */
+ public boolean isEmpty() {
+ return this.bytes.length == 0;
+ }
+
+ // =================================================================
+ // byte[] -> ByteString
+
+ /**
+ * Empty ByteString.
+ */
+ public static final ByteString EMPTY = new ByteString(new byte[0]);
+
+ /**
+ * Copies the given bytes into a {@code ByteString}.
+ */
+ public static ByteString copyFrom(byte[] bytes, int offset, int size) {
+ byte[] copy = new byte[size];
+ System.arraycopy(bytes, offset, copy, 0, size);
+ return new ByteString(copy);
+ }
+
+ /**
+ * Copies the given bytes into a {@code ByteString}.
+ */
+ public static ByteString copyFrom(byte[] bytes) {
+ return copyFrom(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Encodes {@code text} into a sequence of bytes using the named charset
+ * and returns the result as a {@code ByteString}.
+ */
+ public static ByteString copyFrom(String text, String charsetName)
+ throws UnsupportedEncodingException {
+ return new ByteString(text.getBytes(charsetName));
+ }
+
+ /**
+ * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
+ * result as a {@code ByteString}.
+ */
+ public static ByteString copyFromUtf8(String text) {
+ try {
+ return new ByteString(text.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?", e);
+ }
+ }
+
+ // =================================================================
+ // ByteString -> byte[]
+
+ /**
+ * Copies bytes into a buffer at the given offset.
+ *
+ * @param target buffer to copy into
+ * @param offset in the target buffer
+ */
+ public void copyTo(byte[] target, int offset) {
+ System.arraycopy(bytes, 0, target, offset, bytes.length);
+ }
+
+ /**
+ * Copies bytes into a buffer.
+ *
+ * @param target buffer to copy into
+ * @param sourceOffset offset within these bytes
+ * @param targetOffset offset within the target buffer
+ * @param size number of bytes to copy
+ */
+ public void copyTo(byte[] target, int sourceOffset, int targetOffset,
+ int size) {
+ System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
+ }
+
+ /**
+ * Copies bytes to a {@code byte[]}.
+ */
+ public byte[] toByteArray() {
+ int size = this.bytes.length;
+ byte[] copy = new byte[size];
+ System.arraycopy(this.bytes, 0, copy, 0, size);
+ return copy;
+ }
+
+ /**
+ * Constructs a new {@code String} by decoding the bytes using the
+ * specified charset.
+ */
+ public String toString(String charsetName)
+ throws UnsupportedEncodingException {
+ return new String(this.bytes, charsetName);
+ }
+
+ /**
+ * Constructs a new {@code String} by decoding the bytes as UTF-8.
+ */
+ public String toStringUtf8() {
+ try {
+ return new String(this.bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?", e);
+ }
+ }
+
+ // =================================================================
+ // equals() and hashCode()
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof ByteString)) {
+ return false;
+ }
+
+ ByteString other = (ByteString) o;
+ int size = this.bytes.length;
+ if (size != other.bytes.length) {
+ return false;
+ }
+
+ byte[] bytes = this.bytes;
+ byte[] otherBytes = other.bytes;
+ for (int i = 0; i < size; i++) {
+ if (bytes[i] != otherBytes[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ volatile int hash = 0;
+
+ @Override
+ public int hashCode() {
+ int h = this.hash;
+
+ if (h == 0) {
+ byte[] bytes = this.bytes;
+ int size = this.bytes.length;
+
+ h = size;
+ for (int i = 0; i < size; i++) {
+ h = h * 31 + bytes[i];
+ }
+ if (h == 0) {
+ h = 1;
+ }
+
+ this.hash = h;
+ }
+
+ return h;
+ }
+
+ // =================================================================
+ // Input stream
+
+ /**
+ * Creates an {@code InputStream} which can be used to read the bytes.
+ */
+ public InputStream newInput() {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ /**
+ * Creates a {@link CodedInputStream} which can be used to read the bytes.
+ * Using this is more efficient than creating a {@link CodedInputStream}
+ * wrapping the result of {@link #newInput()}.
+ */
+ public CodedInputStream newCodedInput() {
+ // We trust CodedInputStream not to modify the bytes, or to give anyone
+ // else access to them.
+ return CodedInputStream.newInstance(bytes);
+ }
+
+ // =================================================================
+ // Output stream
+
+ /**
+ * Creates a new {@link Output} with the given initial capacity.
+ */
+ public static Output newOutput(int initialCapacity) {
+ return new Output(new ByteArrayOutputStream(initialCapacity));
+ }
+
+ /**
+ * Creates a new {@link Output}.
+ */
+ public static Output newOutput() {
+ return newOutput(32);
+ }
+
+ /**
+ * Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
+ * create the {@code ByteString} instance.
+ */
+ public static final class Output extends FilterOutputStream {
+ private final ByteArrayOutputStream bout;
+
+ /**
+ * Constructs a new output with the given initial capacity.
+ */
+ private Output(ByteArrayOutputStream bout) {
+ super(bout);
+ this.bout = bout;
+ }
+
+ /**
+ * Creates a {@code ByteString} instance from this {@code Output}.
+ */
+ public ByteString toByteString() {
+ byte[] byteArray = bout.toByteArray();
+ return new ByteString(byteArray);
+ }
+ }
+
+ /**
+ * Constructs a new ByteString builder, which allows you to efficiently
+ * construct a {@code ByteString} by writing to a {@link CodedOutputSteam}.
+ * Using this is much more efficient than calling {@code newOutput()} and
+ * wrapping that in a {@code CodedOutputStream}.
+ *
+ * <p>This is package-private because it's a somewhat confusing interface.
+ * Users can call {@link Message#toByteString()} instead of calling this
+ * directly.
+ *
+ * @param size The target byte size of the {@code ByteString}. You must
+ * write exactly this many bytes before building the result.
+ */
+ static CodedBuilder newCodedBuilder(int size) {
+ return new CodedBuilder(size);
+ }
+
+ /** See {@link ByteString#newCodedBuilder(int)}. */
+ static final class CodedBuilder {
+ private final CodedOutputStream output;
+ private final byte[] buffer;
+
+ private CodedBuilder(int size) {
+ buffer = new byte[size];
+ output = CodedOutputStream.newInstance(buffer);
+ }
+
+ public ByteString build() {
+ output.checkNoSpaceLeft();
+
+ // We can be confident that the CodedOutputStream will not modify the
+ // underlying bytes anymore because it already wrote all of them. So,
+ // no need to make a copy.
+ return new ByteString(buffer);
+ }
+
+ public CodedOutputStream getCodedOutput() {
+ return output;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java
new file mode 100644
index 00000000..b32c349c
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -0,0 +1,766 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods: methods that read specific
+ * protocol message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputStream {
+ /**
+ * Create a new CodedInputStream wrapping the given InputStream.
+ */
+ public static CodedInputStream newInstance(InputStream input) {
+ return new CodedInputStream(input);
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping the given byte array.
+ */
+ public static CodedInputStream newInstance(byte[] buf) {
+ return new CodedInputStream(buf);
+ }
+
+ // -----------------------------------------------------------------
+
+ /**
+ * Attempt to read a field tag, returning zero if we have reached EOF.
+ * Protocol message parsers use this to read tags, since a protocol message
+ * may legally end wherever a tag occurs, and zero is not a valid tag number.
+ */
+ public int readTag() throws IOException {
+ if (bufferPos == bufferSize && !refillBuffer(false)) {
+ lastTag = 0;
+ return 0;
+ }
+
+ lastTag = readRawVarint32();
+ if (lastTag == 0) {
+ // If we actually read zero, that's not a valid tag.
+ throw InvalidProtocolBufferException.invalidTag();
+ }
+ return lastTag;
+ }
+
+ /**
+ * Verifies that the last call to readTag() returned the given tag value.
+ * This is used to verify that a nested group ended with the correct
+ * end tag.
+ *
+ * @throws InvalidProtocolBufferException {@code value} does not match the
+ * last tag.
+ */
+ public void checkLastTagWas(int value) throws InvalidProtocolBufferException {
+ if (lastTag != value) {
+ throw InvalidProtocolBufferException.invalidEndTag();
+ }
+ }
+
+ /**
+ * Reads and discards a single field, given its tag value.
+ *
+ * @return {@code false} if the tag is an endgroup tag, in which case
+ * nothing is skipped. Otherwise, returns {@code true}.
+ */
+ public boolean skipField(int tag) throws IOException {
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ readInt32();
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ readRawLittleEndian64();
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ skipRawBytes(readRawVarint32());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ skipMessage();
+ checkLastTagWas(
+ WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+ WireFormat.WIRETYPE_END_GROUP));
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ readRawLittleEndian32();
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Reads and discards an entire message. This will read either until EOF
+ * or until an endgroup tag, whichever comes first.
+ */
+ public void skipMessage() throws IOException {
+ while (true) {
+ int tag = readTag();
+ if (tag == 0 || !skipField(tag)) return;
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Read a {@code double} field value from the stream. */
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readRawLittleEndian64());
+ }
+
+ /** Read a {@code float} field value from the stream. */
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readRawLittleEndian32());
+ }
+
+ /** Read a {@code uint64} field value from the stream. */
+ public long readUInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int64} field value from the stream. */
+ public long readInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ /** Read an {@code int32} field value from the stream. */
+ public int readInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read a {@code fixed64} field value from the stream. */
+ public long readFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read a {@code fixed32} field value from the stream. */
+ public int readFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read a {@code bool} field value from the stream. */
+ public boolean readBool() throws IOException {
+ return readRawVarint32() != 0;
+ }
+
+ /** Read a {@code string} field value from the stream. */
+ public String readString() throws IOException {
+ int size = readRawVarint32();
+ if (size < bufferSize - bufferPos && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ String result = new String(buffer, bufferPos, size, "UTF-8");
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return new String(readRawBytes(size), "UTF-8");
+ }
+ }
+
+ /** Read a {@code group} field value from the stream. */
+ public void readGroup(int fieldNumber, Message.Builder builder,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(
+ WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ }
+
+ /**
+ * Reads a {@code group} field value from the stream and merges it into the
+ * given {@link UnknownFieldSet}.
+ */
+ public void readUnknownGroup(int fieldNumber, UnknownFieldSet.Builder builder)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ builder.mergeFrom(this);
+ checkLastTagWas(
+ WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ }
+
+ /** Read an embedded message field value from the stream. */
+ public void readMessage(Message.Builder builder,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public ByteString readBytes() throws IOException {
+ int size = readRawVarint32();
+ if (size < bufferSize - bufferPos && size > 0) {
+ // Fast path: We already have the bytes in a contiguous buffer, so
+ // just copy directly from it.
+ ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return ByteString.copyFrom(readRawBytes(size));
+ }
+ }
+
+ /** Read a {@code uint32} field value from the stream. */
+ public int readUInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ /**
+ * Read an enum field value from the stream. Caller is responsible
+ * for converting the numeric value to an actual enum.
+ */
+ public int readEnum() throws IOException {
+ return readRawVarint32();
+ }
+
+ /** Read an {@code sfixed32} field value from the stream. */
+ public int readSFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ /** Read an {@code sfixed64} field value from the stream. */
+ public long readSFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ /** Read an {@code sint32} field value from the stream. */
+ public int readSInt32() throws IOException {
+ return decodeZigZag32(readRawVarint32());
+ }
+
+ /** Read an {@code sint64} field value from the stream. */
+ public long readSInt64() throws IOException {
+ return decodeZigZag64(readRawVarint64());
+ }
+
+ /**
+ * Read a field of any primitive type. Enums, groups, and embedded
+ * messages are not handled by this method.
+ *
+ * @param type Declared type of the field.
+ * @return An object representing the field's value, of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public Object readPrimitiveField(
+ Descriptors.FieldDescriptor.Type type) throws IOException {
+ switch (type) {
+ case DOUBLE : return readDouble ();
+ case FLOAT : return readFloat ();
+ case INT64 : return readInt64 ();
+ case UINT64 : return readUInt64 ();
+ case INT32 : return readInt32 ();
+ case FIXED64 : return readFixed64 ();
+ case FIXED32 : return readFixed32 ();
+ case BOOL : return readBool ();
+ case STRING : return readString ();
+ case BYTES : return readBytes ();
+ case UINT32 : return readUInt32 ();
+ case SFIXED32: return readSFixed32();
+ case SFIXED64: return readSFixed64();
+ case SINT32 : return readSInt32 ();
+ case SINT64 : return readSInt64 ();
+
+ case GROUP:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle nested groups.");
+ case MESSAGE:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle embedded messages.");
+ case ENUM:
+ // We don't hanlde enums because we don't know what to do if the
+ // value is not recognized.
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle enums.");
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
+
+ // =================================================================
+
+ /**
+ * Read a raw Varint from the stream. If larger than 32 bits, discard the
+ * upper bits.
+ */
+ public int readRawVarint32() throws IOException {
+ byte tmp = readRawByte();
+ if (tmp >= 0) {
+ return tmp;
+ }
+ int result = tmp & 0x7f;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 7;
+ } else {
+ result |= (tmp & 0x7f) << 7;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 14;
+ } else {
+ result |= (tmp & 0x7f) << 14;
+ if ((tmp = readRawByte()) >= 0) {
+ result |= tmp << 21;
+ } else {
+ result |= (tmp & 0x7f) << 21;
+ result |= (tmp = readRawByte()) << 28;
+ if (tmp < 0) {
+ // Discard upper 32 bits.
+ for (int i = 0; i < 5; i++) {
+ if (readRawByte() >= 0) return result;
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /** Read a raw Varint from the stream. */
+ public long readRawVarint64() throws IOException {
+ int shift = 0;
+ long result = 0;
+ while (shift < 64) {
+ byte b = readRawByte();
+ result |= (long)(b & 0x7F) << shift;
+ if ((b & 0x80) == 0) return result;
+ shift += 7;
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+
+ /** Read a 32-bit little-endian integer from the stream. */
+ public int readRawLittleEndian32() throws IOException {
+ byte b1 = readRawByte();
+ byte b2 = readRawByte();
+ byte b3 = readRawByte();
+ byte b4 = readRawByte();
+ return (((int)b1 & 0xff) ) |
+ (((int)b2 & 0xff) << 8) |
+ (((int)b3 & 0xff) << 16) |
+ (((int)b4 & 0xff) << 24);
+ }
+
+ /** Read a 64-bit little-endian integer from the stream. */
+ public long readRawLittleEndian64() throws IOException {
+ byte b1 = readRawByte();
+ byte b2 = readRawByte();
+ byte b3 = readRawByte();
+ byte b4 = readRawByte();
+ byte b5 = readRawByte();
+ byte b6 = readRawByte();
+ byte b7 = readRawByte();
+ byte b8 = readRawByte();
+ return (((long)b1 & 0xff) ) |
+ (((long)b2 & 0xff) << 8) |
+ (((long)b3 & 0xff) << 16) |
+ (((long)b4 & 0xff) << 24) |
+ (((long)b5 & 0xff) << 32) |
+ (((long)b6 & 0xff) << 40) |
+ (((long)b7 & 0xff) << 48) |
+ (((long)b8 & 0xff) << 56);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 32-bit integer.
+ */
+ public static int decodeZigZag32(int n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ /**
+ * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ * @return A signed 64-bit integer.
+ */
+ public static long decodeZigZag64(long n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ // -----------------------------------------------------------------
+
+ private byte[] buffer;
+ private int bufferSize;
+ private int bufferSizeAfterLimit = 0;
+ private int bufferPos = 0;
+ private InputStream input;
+ private int lastTag = 0;
+
+ /**
+ * The total number of bytes read before the current buffer. The total
+ * bytes read up to the current position can be computed as
+ * {@code totalBytesRetired + bufferPos}.
+ */
+ private int totalBytesRetired = 0;
+
+ /** The absolute position of the end of the current message. */
+ private int currentLimit = Integer.MAX_VALUE;
+
+ /** See setRecursionLimit() */
+ private int recursionDepth = 0;
+ private int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+ /** See setSizeLimit() */
+ private int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+ private static final int DEFAULT_RECURSION_LIMIT = 64;
+ private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
+ private static final int BUFFER_SIZE = 4096;
+
+ private CodedInputStream(byte[] buffer) {
+ this.buffer = buffer;
+ this.bufferSize = buffer.length;
+ this.input = null;
+ }
+
+ private CodedInputStream(InputStream input) {
+ this.buffer = new byte[BUFFER_SIZE];
+ this.bufferSize = 0;
+ this.input = input;
+ }
+
+ /**
+ * Set the maximum message recursion depth. In order to prevent malicious
+ * messages from causing stack overflows, {@code CodedInputStream} limits
+ * how deeply messages may be nested. The default limit is 64.
+ *
+ * @return the old limit.
+ */
+ public int setRecursionLimit(int limit) {
+ if (limit < 0) {
+ throw new IllegalArgumentException(
+ "Recursion limit cannot be negative: " + limit);
+ }
+ int oldLimit = recursionLimit;
+ recursionLimit = limit;
+ return oldLimit;
+ }
+
+ /**
+ * Set the maximum message size. In order to prevent malicious
+ * messages from exhausting memory or causing integer overflows,
+ * {@code CodedInputStream} limits how large a message may be.
+ * The default limit is 64MB. You should set this limit as small
+ * as you can without harming your app's functionality. Note that
+ * size limits only apply when reading from an {@code InputStream}, not
+ * when constructed around a raw byte array (nor with
+ * {@link ByteString#newCodedInput}).
+ *
+ * @return the old limit.
+ */
+ public int setSizeLimit(int limit) {
+ if (limit < 0) {
+ throw new IllegalArgumentException(
+ "Size limit cannot be negative: " + limit);
+ }
+ int oldLimit = sizeLimit;
+ sizeLimit = limit;
+ return oldLimit;
+ }
+
+ /**
+ * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
+ * is called when descending into a length-delimited embedded message.
+ *
+ * @return the old limit.
+ */
+ public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+ if (byteLimit < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ byteLimit += totalBytesRetired + bufferPos;
+ int oldLimit = currentLimit;
+ if (byteLimit > oldLimit) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ currentLimit = byteLimit;
+
+ recomputeBufferSizeAfterLimit();
+
+ return oldLimit;
+ }
+
+ private void recomputeBufferSizeAfterLimit() {
+ bufferSize += bufferSizeAfterLimit;
+ int bufferEnd = totalBytesRetired + bufferSize;
+ if (bufferEnd > currentLimit) {
+ // Limit is in current buffer.
+ bufferSizeAfterLimit = bufferEnd - currentLimit;
+ bufferSize -= bufferSizeAfterLimit;
+ } else {
+ bufferSizeAfterLimit = 0;
+ }
+ }
+
+ /**
+ * Discards the current limit, returning to the previous limit.
+ *
+ * @param oldLimit The old limit, as returned by {@code pushLimit}.
+ */
+ public void popLimit(int oldLimit) {
+ currentLimit = oldLimit;
+ recomputeBufferSizeAfterLimit();
+ }
+
+ /**
+ * Called with {@code this.buffer} is empty to read more bytes from the
+ * input. If {@code mustSucceed} is true, refillBuffer() gurantees that
+ * either there will be at least one byte in the buffer when it returns
+ * or it will throw an exception. If {@code mustSucceed} is false,
+ * refillBuffer() returns false if no more bytes were available.
+ */
+ private boolean refillBuffer(boolean mustSucceed) throws IOException {
+ if (bufferPos < bufferSize) {
+ throw new IllegalStateException(
+ "refillBuffer() called when buffer wasn't empty.");
+ }
+
+ if (totalBytesRetired + bufferSize == currentLimit) {
+ // Oops, we hit a limit.
+ if (mustSucceed) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ } else {
+ return false;
+ }
+ }
+
+ totalBytesRetired += bufferSize;
+
+ bufferPos = 0;
+ bufferSize = (input == null) ? -1 : input.read(buffer);
+ if (bufferSize == -1) {
+ bufferSize = 0;
+ if (mustSucceed) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ } else {
+ return false;
+ }
+ } else {
+ recomputeBufferSizeAfterLimit();
+ int totalBytesRead =
+ totalBytesRetired + bufferSize + bufferSizeAfterLimit;
+ if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
+ throw InvalidProtocolBufferException.sizeLimitExceeded();
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Read one byte from the input.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ public byte readRawByte() throws IOException {
+ if (bufferPos == bufferSize) {
+ refillBuffer(true);
+ }
+ return buffer[bufferPos++];
+ }
+
+ /**
+ * Read a fixed size of bytes from the input.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ public byte[] readRawBytes(int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+
+ if (totalBytesRetired + bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ if (size <= bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ byte[] bytes = new byte[size];
+ System.arraycopy(buffer, bufferPos, bytes, 0, size);
+ bufferPos += size;
+ return bytes;
+ } else if (size < BUFFER_SIZE) {
+ // Reading more bytes than are in the buffer, but not an excessive number
+ // of bytes. We can safely allocate the resulting array ahead of time.
+
+ // First copy what we have.
+ byte[] bytes = new byte[size];
+ int pos = bufferSize - bufferPos;
+ System.arraycopy(buffer, bufferPos, bytes, 0, pos);
+ bufferPos = bufferSize;
+
+ // We want to use refillBuffer() and then copy from the buffer into our
+ // byte array rather than reading directly into our byte array because
+ // the input may be unbuffered.
+ refillBuffer(true);
+
+ while (size - pos > bufferSize) {
+ System.arraycopy(buffer, 0, bytes, pos, bufferSize);
+ pos += bufferSize;
+ bufferPos = bufferSize;
+ refillBuffer(true);
+ }
+
+ System.arraycopy(buffer, 0, bytes, pos, size - pos);
+ bufferPos = size - pos;
+
+ return bytes;
+ } else {
+ // The size is very large. For security reasons, we can't allocate the
+ // entire byte array yet. The size comes directly from the input, so a
+ // maliciously-crafted message could provide a bogus very large size in
+ // order to trick the app into allocating a lot of memory. We avoid this
+ // by allocating and reading only a small chunk at a time, so that the
+ // malicious message must actually *be* extremely large to cause
+ // problems. Meanwhile, we limit the allowed size of a message elsewhere.
+
+ // Remember the buffer markers since we'll have to copy the bytes out of
+ // it later.
+ int originalBufferPos = bufferPos;
+ int originalBufferSize = bufferSize;
+
+ // Mark the current buffer consumed.
+ totalBytesRetired += bufferSize;
+ bufferPos = 0;
+ bufferSize = 0;
+
+ // Read all the rest of the bytes we need.
+ int sizeLeft = size - (originalBufferSize - originalBufferPos);
+ List<byte[]> chunks = new ArrayList<byte[]>();
+
+ while (sizeLeft > 0) {
+ byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
+ int pos = 0;
+ while (pos < chunk.length) {
+ int n = (input == null) ? -1 :
+ input.read(chunk, pos, chunk.length - pos);
+ if (n == -1) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ totalBytesRetired += n;
+ pos += n;
+ }
+ sizeLeft -= chunk.length;
+ chunks.add(chunk);
+ }
+
+ // OK, got everything. Now concatenate it all into one buffer.
+ byte[] bytes = new byte[size];
+
+ // Start by copying the leftover bytes from this.buffer.
+ int pos = originalBufferSize - originalBufferPos;
+ System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
+
+ // And now all the chunks.
+ for (byte[] chunk : chunks) {
+ System.arraycopy(chunk, 0, bytes, pos, chunk.length);
+ pos += chunk.length;
+ }
+
+ // Done.
+ return bytes;
+ }
+ }
+
+ /**
+ * Reads and discards {@code size} bytes.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ public void skipRawBytes(int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+
+ if (totalBytesRetired + bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ if (size < bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ bufferPos += size;
+ } else {
+ // Skipping more bytes than are in the buffer. First skip what we have.
+ int pos = bufferSize - bufferPos;
+ totalBytesRetired += pos;
+ bufferPos = 0;
+ bufferSize = 0;
+
+ // Then skip directly from the InputStream for the rest.
+ while (pos < size) {
+ int n = (input == null) ? -1 : (int) input.skip(size - pos);
+ if (n <= 0) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ pos += n;
+ totalBytesRetired += n;
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
new file mode 100644
index 00000000..18498999
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -0,0 +1,775 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ * <p>This class contains two kinds of methods: methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputStream {
+ private final byte[] buffer;
+ private final int limit;
+ private int position;
+
+ private final OutputStream output;
+
+ /**
+ * The buffer size used in {@link #newInstance(java.io.OutputStream)}.
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 4096;
+
+ private CodedOutputStream(byte[] buffer, int offset, int length) {
+ this.output = null;
+ this.buffer = buffer;
+ this.position = offset;
+ this.limit = offset + length;
+ }
+
+ private CodedOutputStream(OutputStream output, byte[] buffer) {
+ this.output = output;
+ this.buffer = buffer;
+ this.position = 0;
+ this.limit = buffer.length;
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} wrapping the given
+ * {@code OutputStream}.
+ */
+ public static CodedOutputStream newInstance(OutputStream output) {
+ return newInstance(output, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} wrapping the given
+ * {@code OutputStream} with a given buffer size.
+ */
+ public static CodedOutputStream newInstance(OutputStream output,
+ int bufferSize) {
+ return new CodedOutputStream(output, new byte[bufferSize]);
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} that writes directly to the given
+ * byte array. If more bytes are written than fit in the array,
+ * {@link OutOfSpaceException} will be thrown. Writing directly to a flat
+ * array is faster than writing to an {@code OutputStream}. See also
+ * {@link ByteString#newCodedBuilder}.
+ */
+ public static CodedOutputStream newInstance(byte[] flatArray) {
+ return newInstance(flatArray, 0, flatArray.length);
+ }
+
+ /**
+ * Create a new {@code CodedOutputStream} that writes directly to the given
+ * byte array slice. If more bytes are written than fit in the slice,
+ * {@link OutOfSpaceException} will be thrown. Writing directly to a flat
+ * array is faster than writing to an {@code OutputStream}. See also
+ * {@link ByteString#newCodedBuilder}.
+ */
+ public static CodedOutputStream newInstance(byte[] flatArray, int offset,
+ int length) {
+ return new CodedOutputStream(flatArray, offset, length);
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field, including tag, to the stream. */
+ public void writeDouble(int fieldNumber, double value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(Double.doubleToRawLongBits(value));
+ }
+
+ /** Write a {@code float} field, including tag, to the stream. */
+ public void writeFloat(int fieldNumber, float value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(Float.floatToRawIntBits(value));
+ }
+
+ /** Write a {@code uint64} field, including tag, to the stream. */
+ public void writeUInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int64} field, including tag, to the stream. */
+ public void writeInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int32} field, including tag, to the stream. */
+ public void writeInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ if (value >= 0) {
+ writeRawVarint32(value);
+ } else {
+ // Must sign-extend.
+ writeRawVarint64(value);
+ }
+ }
+
+ /** Write a {@code fixed64} field, including tag, to the stream. */
+ public void writeFixed64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write a {@code fixed32} field, including tag, to the stream. */
+ public void writeFixed32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write a {@code bool} field, including tag, to the stream. */
+ public void writeBool(int fieldNumber, boolean value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawByte(value ? 1 : 0);
+ }
+
+ /** Write a {@code string} field, including tag, to the stream. */
+ public void writeString(int fieldNumber, String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ // Unfortunately there does not appear to be any way to tell Java to encode
+ // UTF-8 directly into our buffer, so we have to let it create its own byte
+ // array and then copy.
+ byte[] bytes = value.getBytes("UTF-8");
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code group} field, including tag, to the stream. */
+ public void writeGroup(int fieldNumber, Message value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+ value.writeTo(this);
+ writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ /** Write a group represented by an {@link UnknownFieldSet}. */
+ public void writeUnknownGroup(int fieldNumber, UnknownFieldSet value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+ value.writeTo(this);
+ writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ /** Write an embedded message field, including tag, to the stream. */
+ public void writeMessage(int fieldNumber, Message value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeRawVarint32(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeBytes(int fieldNumber, ByteString value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ byte[] bytes = value.toByteArray();
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code uint32} field, including tag, to the stream. */
+ public void writeUInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(value);
+ }
+
+ /**
+ * Write an enum field, including tag, to the stream. Caller is responsible
+ * for converting the enum value to its numeric value.
+ */
+ public void writeEnum(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(value);
+ }
+
+ /** Write an {@code sfixed32} field, including tag, to the stream. */
+ public void writeSFixed32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write an {@code sfixed64} field, including tag, to the stream. */
+ public void writeSFixed64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write an {@code sint32} field, including tag, to the stream. */
+ public void writeSInt32(int fieldNumber, int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint32(encodeZigZag32(value));
+ }
+
+ /** Write an {@code sint64} field, including tag, to the stream. */
+ public void writeSInt64(int fieldNumber, long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeRawVarint64(encodeZigZag64(value));
+ }
+
+ /**
+ * Write a MessageSet extension field to the stream. For historical reasons,
+ * the wire format differs from normal fields.
+ */
+ public void writeMessageSetExtension(int fieldNumber, Message value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ /**
+ * Write an unparsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
+ */
+ public void writeRawMessageSetExtension(int fieldNumber, ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ /**
+ * Write a field of arbitrary type, including tag, to the stream.
+ *
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public void writeField(Descriptors.FieldDescriptor.Type type,
+ int number, Object value) throws IOException {
+ switch (type) {
+ case DOUBLE : writeDouble (number, (Double )value); break;
+ case FLOAT : writeFloat (number, (Float )value); break;
+ case INT64 : writeInt64 (number, (Long )value); break;
+ case UINT64 : writeUInt64 (number, (Long )value); break;
+ case INT32 : writeInt32 (number, (Integer )value); break;
+ case FIXED64 : writeFixed64 (number, (Long )value); break;
+ case FIXED32 : writeFixed32 (number, (Integer )value); break;
+ case BOOL : writeBool (number, (Boolean )value); break;
+ case STRING : writeString (number, (String )value); break;
+ case GROUP : writeGroup (number, (Message )value); break;
+ case MESSAGE : writeMessage (number, (Message )value); break;
+ case BYTES : writeBytes (number, (ByteString)value); break;
+ case UINT32 : writeUInt32 (number, (Integer )value); break;
+ case SFIXED32: writeSFixed32(number, (Integer )value); break;
+ case SFIXED64: writeSFixed64(number, (Long )value); break;
+ case SINT32 : writeSInt32 (number, (Integer )value); break;
+ case SINT64 : writeSInt64 (number, (Long )value); break;
+
+ case ENUM:
+ writeEnum(number, ((Descriptors.EnumValueDescriptor)value).getNumber());
+ break;
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code double} field, including tag.
+ */
+ public static int computeDoubleSize(int fieldNumber, double value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code float} field, including tag.
+ */
+ public static int computeFloatSize(int fieldNumber, float value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint64} field, including tag.
+ */
+ public static int computeUInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int64} field, including tag.
+ */
+ public static int computeInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int32} field, including tag.
+ */
+ public static int computeInt32Size(int fieldNumber, int value) {
+ if (value >= 0) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ } else {
+ // Must sign-extend.
+ return computeTagSize(fieldNumber) + 10;
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed64} field, including tag.
+ */
+ public static int computeFixed64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed32} field, including tag.
+ */
+ public static int computeFixed32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bool} field, including tag.
+ */
+ public static int computeBoolSize(int fieldNumber, boolean value) {
+ return computeTagSize(fieldNumber) + 1;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code string} field, including tag.
+ */
+ public static int computeStringSize(int fieldNumber, String value) {
+ try {
+ byte[] bytes = value.getBytes("UTF-8");
+ return computeTagSize(fieldNumber) +
+ computeRawVarint32Size(bytes.length) +
+ bytes.length;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field, including tag.
+ */
+ public static int computeGroupSize(int fieldNumber, Message value) {
+ return computeTagSize(fieldNumber) * 2 + value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field represented by an {@code UnknownFieldSet}, including
+ * tag.
+ */
+ public static int computeUnknownGroupSize(int fieldNumber,
+ UnknownFieldSet value) {
+ return computeTagSize(fieldNumber) * 2 + value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * embedded message field, including tag.
+ */
+ public static int computeMessageSize(int fieldNumber, Message value) {
+ int size = value.getSerializedSize();
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(size) + size;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field, including tag.
+ */
+ public static int computeBytesSize(int fieldNumber, ByteString value) {
+ return computeTagSize(fieldNumber) +
+ computeRawVarint32Size(value.size()) +
+ value.size();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint32} field, including tag.
+ */
+ public static int computeUInt32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * enum field, including tag. Caller is responsible for converting the
+ * enum value to its numeric value.
+ */
+ public static int computeEnumSize(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed32} field, including tag.
+ */
+ public static int computeSFixed32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed64} field, including tag.
+ */
+ public static int computeSFixed64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint32} field, including tag.
+ */
+ public static int computeSInt32Size(int fieldNumber, int value) {
+ return computeTagSize(fieldNumber) +
+ computeRawVarint32Size(encodeZigZag32(value));
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint64} field, including tag.
+ */
+ public static int computeSInt64Size(int fieldNumber, long value) {
+ return computeTagSize(fieldNumber) +
+ computeRawVarint64Size(encodeZigZag64(value));
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * MessageSet extension to the stream. For historical reasons,
+ * the wire format differs from normal fields.
+ */
+ public static int computeMessageSetExtensionSize(
+ int fieldNumber, Message value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
+ computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
+ computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * unparsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
+ */
+ public static int computeRawMessageSetExtensionSize(
+ int fieldNumber, ByteString value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
+ computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
+ computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * field of arbitrary type, including tag, to the stream.
+ *
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public static int computeFieldSize(
+ Descriptors.FieldDescriptor.Type type,
+ int number, Object value) {
+ switch (type) {
+ case DOUBLE : return computeDoubleSize (number, (Double )value);
+ case FLOAT : return computeFloatSize (number, (Float )value);
+ case INT64 : return computeInt64Size (number, (Long )value);
+ case UINT64 : return computeUInt64Size (number, (Long )value);
+ case INT32 : return computeInt32Size (number, (Integer )value);
+ case FIXED64 : return computeFixed64Size (number, (Long )value);
+ case FIXED32 : return computeFixed32Size (number, (Integer )value);
+ case BOOL : return computeBoolSize (number, (Boolean )value);
+ case STRING : return computeStringSize (number, (String )value);
+ case GROUP : return computeGroupSize (number, (Message )value);
+ case MESSAGE : return computeMessageSize (number, (Message )value);
+ case BYTES : return computeBytesSize (number, (ByteString)value);
+ case UINT32 : return computeUInt32Size (number, (Integer )value);
+ case SFIXED32: return computeSFixed32Size(number, (Integer )value);
+ case SFIXED64: return computeSFixed64Size(number, (Long )value);
+ case SINT32 : return computeSInt32Size (number, (Integer )value);
+ case SINT64 : return computeSInt64Size (number, (Long )value);
+
+ case ENUM:
+ return computeEnumSize(number,
+ ((Descriptors.EnumValueDescriptor)value).getNumber());
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
+
+ // =================================================================
+
+ /**
+ * Internal helper that writes the current buffer to the output. The
+ * buffer position is reset to its initial value when this returns.
+ */
+ private void refreshBuffer() throws IOException {
+ if (output == null) {
+ // We're writing to a single buffer.
+ throw new OutOfSpaceException();
+ }
+
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ output.write(buffer, 0, position);
+ position = 0;
+ }
+
+ /**
+ * Flushes the stream and forces any buffered bytes to be written. This
+ * does not flush the underlying OutputStream.
+ */
+ public void flush() throws IOException {
+ if (output != null) {
+ refreshBuffer();
+ }
+ }
+
+ /**
+ * If writing to a flat array, return the space left in the array.
+ * Otherwise, throws {@code UnsupportedOperationException}.
+ */
+ public int spaceLeft() {
+ if (output == null) {
+ return limit - position;
+ } else {
+ throw new UnsupportedOperationException(
+ "spaceLeft() can only be called on CodedOutputStreams that are " +
+ "writing to a flat array.");
+ }
+ }
+
+ /**
+ * Verifies that {@link #spaceLeft()} returns zero. It's common to create
+ * a byte array that is exactly big enough to hold a message, then write to
+ * it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()}
+ * after writing verifies that the message was actually as big as expected,
+ * which can help catch bugs.
+ */
+ public void checkNoSpaceLeft() {
+ if (spaceLeft() != 0) {
+ throw new IllegalStateException(
+ "Did not write as much data as expected.");
+ }
+ }
+
+ /**
+ * If you create a CodedOutputStream around a simple flat array, you must
+ * not attempt to write more bytes than the array has space. Otherwise,
+ * this exception will be thrown.
+ */
+ public static class OutOfSpaceException extends IOException {
+ OutOfSpaceException() {
+ super("CodedOutputStream was writing to a flat byte array and ran " +
+ "out of space.");
+ }
+ }
+
+ /** Write a single byte. */
+ public void writeRawByte(byte value) throws IOException {
+ if (position == limit) {
+ refreshBuffer();
+ }
+
+ buffer[position++] = value;
+ }
+
+ /** Write a single byte, represented by an integer value. */
+ public void writeRawByte(int value) throws IOException {
+ writeRawByte((byte) value);
+ }
+
+ /** Write an array of bytes. */
+ public void writeRawBytes(byte[] value) throws IOException {
+ writeRawBytes(value, 0, value.length);
+ }
+
+ /** Write part of an array of bytes. */
+ public void writeRawBytes(byte[] value, int offset, int length)
+ throws IOException {
+ if (limit - position >= length) {
+ // We have room in the current buffer.
+ System.arraycopy(value, offset, buffer, position, length);
+ position += length;
+ } else {
+ // Write extends past current buffer. Fill the rest of this buffer and
+ // flush.
+ int bytesWritten = limit - position;
+ System.arraycopy(value, offset, buffer, position, bytesWritten);
+ offset += bytesWritten;
+ length -= bytesWritten;
+ position = limit;
+ refreshBuffer();
+
+ // Now deal with the rest.
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ if (length <= limit) {
+ // Fits in new buffer.
+ System.arraycopy(value, offset, buffer, 0, length);
+ position = length;
+ } else {
+ // Write is very big. Let's do it all at once.
+ output.write(value, offset, length);
+ }
+ }
+ }
+
+ /** Encode and write a tag. */
+ public void writeTag(int fieldNumber, int wireType) throws IOException {
+ writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ /** Compute the number of bytes that would be needed to encode a tag. */
+ public static int computeTagSize(int fieldNumber) {
+ return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
+ }
+
+ /**
+ * Encode and write a varint. {@code value} is treated as
+ * unsigned, so it won't be sign-extended if negative.
+ */
+ public void writeRawVarint32(int value) throws IOException {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ writeRawByte(value);
+ return;
+ } else {
+ writeRawByte((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a varint.
+ * {@code value} is treated as unsigned, so it won't be sign-extended if
+ * negative.
+ */
+ public static int computeRawVarint32Size(int value) {
+ if ((value & (0xffffffff << 7)) == 0) return 1;
+ if ((value & (0xffffffff << 14)) == 0) return 2;
+ if ((value & (0xffffffff << 21)) == 0) return 3;
+ if ((value & (0xffffffff << 28)) == 0) return 4;
+ return 5;
+ }
+
+ /** Encode and write a varint. */
+ public void writeRawVarint64(long value) throws IOException {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ writeRawByte((int)value);
+ return;
+ } else {
+ writeRawByte(((int)value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ /** Compute the number of bytes that would be needed to encode a varint. */
+ public static int computeRawVarint64Size(long value) {
+ if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
+ if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+ if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+ if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+ if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+ if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+ if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+ if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+ if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+ return 10;
+ }
+
+ /** Write a little-endian 32-bit integer. */
+ public void writeRawLittleEndian32(int value) throws IOException {
+ writeRawByte((value ) & 0xFF);
+ writeRawByte((value >> 8) & 0xFF);
+ writeRawByte((value >> 16) & 0xFF);
+ writeRawByte((value >> 24) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_32_SIZE = 4;
+
+ /** Write a little-endian 64-bit integer. */
+ public void writeRawLittleEndian64(long value) throws IOException {
+ writeRawByte((int)(value ) & 0xFF);
+ writeRawByte((int)(value >> 8) & 0xFF);
+ writeRawByte((int)(value >> 16) & 0xFF);
+ writeRawByte((int)(value >> 24) & 0xFF);
+ writeRawByte((int)(value >> 32) & 0xFF);
+ writeRawByte((int)(value >> 40) & 0xFF);
+ writeRawByte((int)(value >> 48) & 0xFF);
+ writeRawByte((int)(value >> 56) & 0xFF);
+ }
+
+ public static final int LITTLE_ENDIAN_64_SIZE = 8;
+
+ /**
+ * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 32-bit integer.
+ * @return An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ */
+ public static int encodeZigZag32(int n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 31);
+ }
+
+ /**
+ * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 64-bit integer.
+ * @return An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
+ */
+ public static long encodeZigZag64(long n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 63);
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
new file mode 100644
index 00000000..9ad8e521
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Descriptors.java
@@ -0,0 +1,1635 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.DescriptorProtos.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains a collection of classes which describe protocol message types.
+ *
+ * Every message type has a {@link Descriptors.Descriptor}, which lists all
+ * its fields and other information about a type. You can get a message
+ * type's descriptor by calling {@code MessageType.getDescriptor()}, or
+ * (given a message object of the type) {@code message.getDescriptorForType()}.
+ *
+ * Descriptors are built from DescriptorProtos, as defined in
+ * {@code net/proto2/proto/descriptor.proto}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class Descriptors {
+ /**
+ * Describes a {@code .proto} file, including everything defined within.
+ */
+ public static final class FileDescriptor {
+ /** Convert the descriptor to its protocol message representation. */
+ public FileDescriptorProto toProto() { return proto; }
+
+ /** Get the file name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the proto package name. This is the package name given by the
+ * {@code package} statement in the {@code .proto} file, which differs
+ * from the Java package.
+ */
+ public String getPackage() { return proto.getPackage(); }
+
+ /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
+ public FileOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of top-level message types declared in this file. */
+ public List<Descriptor> getMessageTypes() {
+ return Collections.unmodifiableList(Arrays.asList(messageTypes));
+ }
+
+ /** Get a list of top-level enum types declared in this file. */
+ public List<EnumDescriptor> getEnumTypes() {
+ return Collections.unmodifiableList(Arrays.asList(enumTypes));
+ }
+
+ /** Get a list of top-level services declared in this file. */
+ public List<ServiceDescriptor> getServices() {
+ return Collections.unmodifiableList(Arrays.asList(services));
+ }
+
+ /** Get a list of top-level extensions declared in this file. */
+ public List<FieldDescriptor> getExtensions() {
+ return Collections.unmodifiableList(Arrays.asList(extensions));
+ }
+
+ /** Get a list of this file's dependencies (imports). */
+ public List<FileDescriptor> getDependencies() {
+ return Collections.unmodifiableList(Arrays.asList(dependencies));
+ }
+
+ /**
+ * Find a message type in the file by name. Does not find nested types.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The message type's descriptor, or {@code null} if not found.
+ */
+ public Descriptor findMessageTypeByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) return null;
+ if (getPackage().length() > 0) {
+ name = getPackage() + "." + name;
+ }
+ GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof Descriptor &&
+ result.getFile() == this) {
+ return (Descriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an enum type in the file by name. Does not find nested types.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The enum type's descriptor, or {@code null} if not found.
+ */
+ public EnumDescriptor findEnumTypeByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) return null;
+ if (getPackage().length() > 0) {
+ name = getPackage() + "." + name;
+ }
+ GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof EnumDescriptor &&
+ result.getFile() == this) {
+ return (EnumDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find a service type in the file by name.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The service type's descriptor, or {@code null} if not found.
+ */
+ public ServiceDescriptor findServiceByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) return null;
+ if (getPackage().length() > 0) {
+ name = getPackage() + "." + name;
+ }
+ GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof ServiceDescriptor &&
+ result.getFile() == this) {
+ return (ServiceDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an extension in the file by name. Does not find extensions nested
+ * inside message types.
+ *
+ * @param name The unqualified extension name to look for.
+ * @return The extension's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findExtensionByName(String name) {
+ if (name.indexOf('.') != -1) return null;
+ if (getPackage().length() > 0) {
+ name = getPackage() + "." + name;
+ }
+ GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof FieldDescriptor &&
+ result.getFile() == this) {
+ return (FieldDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Construct a {@code FileDescriptor}.
+ *
+ * @param proto The protocol message form of the FileDescriptor.
+ * @param dependencies {@code FileDescriptor}s corresponding to all of
+ * the file's dependencies, in the exact order listed
+ * in {@code proto}.
+ * @throws DescriptorValidationException {@code proto} is not a valid
+ * descriptor. This can occur for a number of reasons, e.g.
+ * because a field has an undefined type or because two messages
+ * were defined with the same name.
+ */
+ public static FileDescriptor buildFrom(FileDescriptorProto proto,
+ FileDescriptor[] dependencies)
+ throws DescriptorValidationException {
+ // Building decsriptors involves two steps: translating and linking.
+ // In the translation step (implemented by FileDescriptor's
+ // constructor), we build an object tree mirroring the
+ // FileDescriptorProto's tree and put all of the descriptors into the
+ // DescriptorPool's lookup tables. In the linking step, we look up all
+ // type references in the DescriptorPool, so that, for example, a
+ // FieldDescriptor for an embedded message contains a pointer directly
+ // to the Descriptor for that message's type. We also detect undefined
+ // types in the linking step.
+ DescriptorPool pool = new DescriptorPool(dependencies);
+ FileDescriptor result = new FileDescriptor(proto, dependencies, pool);
+
+ if (dependencies.length != proto.getDependencyCount()) {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.buildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ for (int i = 0; i < proto.getDependencyCount(); i++) {
+ if (!dependencies[i].getName().equals(proto.getDependency(i))) {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.buildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ }
+
+ result.crossLink();
+ return result;
+ }
+
+ /**
+ * This method is to be called by generated code only. It is equivalent
+ * to {@code buildFrom} except that the {@code FileDescriptorProto} is
+ * encoded in protocol buffer wire format.
+ */
+ public static FileDescriptor internalBuildGeneratedFileFrom(
+ String descriptorData, FileDescriptor[] dependencies)
+ throws DescriptorValidationException,
+ InvalidProtocolBufferException {
+ // Hack: We can't embed a raw byte array inside generated Java code
+ // (at least, not efficiently), but we can embed Strings. So, the
+ // protocol compiler embeds the FileDescriptorProto as a giant
+ // string literal which is passed to this function to construct the
+ // file's FileDescriptor. The string literal contains only 8-bit
+ // characters, each one representing a byte of the FileDescriptorProto's
+ // serialized form. So, if we convert it to bytes in ISO-8859-1, we
+ // should get the original bytes that we want.
+ try {
+ FileDescriptorProto proto =
+ FileDescriptorProto.parseFrom(descriptorData.getBytes("ISO-8859-1"));
+ return buildFrom(proto, dependencies);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(
+ "Standard encoding ISO-8859-1 not supported by JVM.", e);
+ }
+ }
+
+ private final FileDescriptorProto proto;
+ private final Descriptor[] messageTypes;
+ private final EnumDescriptor[] enumTypes;
+ private final ServiceDescriptor[] services;
+ private final FieldDescriptor[] extensions;
+ private final FileDescriptor[] dependencies;
+ private final DescriptorPool pool;
+
+ private FileDescriptor(FileDescriptorProto proto,
+ FileDescriptor[] dependencies,
+ DescriptorPool pool)
+ throws DescriptorValidationException {
+ this.pool = pool;
+ this.proto = proto;
+ this.dependencies = dependencies.clone();
+
+ pool.addPackage(getPackage(), this);
+
+ messageTypes = new Descriptor[proto.getMessageTypeCount()];
+ for (int i = 0; i < proto.getMessageTypeCount(); i++) {
+ messageTypes[i] =
+ new Descriptor(proto.getMessageType(i), this, null, i);
+ }
+
+ enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+ for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+ enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
+ }
+
+ services = new ServiceDescriptor[proto.getServiceCount()];
+ for (int i = 0; i < proto.getServiceCount(); i++) {
+ services[i] = new ServiceDescriptor(proto.getService(i), this, i);
+ }
+
+ extensions = new FieldDescriptor[proto.getExtensionCount()];
+ for (int i = 0; i < proto.getExtensionCount(); i++) {
+ extensions[i] = new FieldDescriptor(
+ proto.getExtension(i), this, null, i, true);
+ }
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ for (int i = 0; i < messageTypes.length; i++) {
+ messageTypes[i].crossLink();
+ }
+
+ for (int i = 0; i < services.length; i++) {
+ services[i].crossLink();
+ }
+
+ for (int i = 0; i < extensions.length; i++) {
+ extensions[i].crossLink();
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a message type. */
+ public static final class Descriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent. In other words,
+ * given a {@link FileDescriptor} {@code file}, the following is true:
+ * <pre>
+ * for all i in [0, file.getMessageTypeCount()):
+ * file.getMessageType(i).getIndex() == i
+ * </pre>
+ * Similarly, for a {@link Descriptor} {@code messageType}:
+ * <pre>
+ * for all i in [0, messageType.getNestedTypeCount()):
+ * messageType.getNestedType(i).getIndex() == i
+ * </pre>
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public DescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name, within the proto language's
+ * namespace. This differs from the Java name. For example, given this
+ * {@code .proto}:
+ * <pre>
+ * package foo.bar;
+ * option java_package = "com.example.protos"
+ * message Baz {}
+ * </pre>
+ * {@code Baz}'s full name is "foo.bar.Baz".
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** If this is a nested type, get the outer descriptor, otherwise null. */
+ public Descriptor getContainingType() { return containingType; }
+
+ /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
+ public MessageOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of this message type's fields. */
+ public List<FieldDescriptor> getFields() {
+ return Collections.unmodifiableList(Arrays.asList(fields));
+ }
+
+ /** Get a list of this message type's extensions. */
+ public List<FieldDescriptor> getExtensions() {
+ return Collections.unmodifiableList(Arrays.asList(extensions));
+ }
+
+ /** Get a list of message types nested within this one. */
+ public List<Descriptor> getNestedTypes() {
+ return Collections.unmodifiableList(Arrays.asList(nestedTypes));
+ }
+
+ /** Get a list of enum types nested within this one. */
+ public List<EnumDescriptor> getEnumTypes() {
+ return Collections.unmodifiableList(Arrays.asList(enumTypes));
+ }
+
+ /** Determines if the given field number is an extension. */
+ public boolean isExtensionNumber(int number) {
+ for (DescriptorProto.ExtensionRange range : proto.getExtensionRangeList()) {
+ if (range.getStart() <= number && number < range.getEnd()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds a field by name.
+ * @param name The unqualified name of the field (e.g. "foo").
+ * @return The field's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findFieldByName(String name) {
+ GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
+ if (result != null && result instanceof FieldDescriptor) {
+ return (FieldDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds a field by field number.
+ * @param number The field number within this message type.
+ * @return The field's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findFieldByNumber(int number) {
+ return file.pool.fieldsByNumber.get(
+ new DescriptorPool.DescriptorIntPair(this, number));
+ }
+
+ /**
+ * Finds a nested message type by name.
+ * @param name The unqualified name of the nested type (e.g. "Foo").
+ * @return The types's descriptor, or {@code null} if not found.
+ */
+ public Descriptor findNestedTypeByName(String name) {
+ GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
+ if (result != null && result instanceof Descriptor) {
+ return (Descriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds a nested enum type by name.
+ * @param name The unqualified name of the nested type (e.g. "Foo").
+ * @return The types's descriptor, or {@code null} if not found.
+ */
+ public EnumDescriptor findEnumTypeByName(String name) {
+ GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
+ if (result != null && result instanceof EnumDescriptor) {
+ return (EnumDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ private final int index;
+ private final DescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor containingType;
+ private final Descriptor[] nestedTypes;
+ private final EnumDescriptor[] enumTypes;
+ private final FieldDescriptor[] fields;
+ private final FieldDescriptor[] extensions;
+
+ private Descriptor(DescriptorProto proto,
+ FileDescriptor file,
+ Descriptor parent,
+ int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+ this.containingType = parent;
+
+ this.nestedTypes = new Descriptor[proto.getNestedTypeCount()];
+ for (int i = 0; i < proto.getNestedTypeCount(); i++) {
+ this.nestedTypes[i] = new Descriptor(
+ proto.getNestedType(i), file, this, i);
+ }
+
+ this.enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+ for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+ this.enumTypes[i] = new EnumDescriptor(
+ proto.getEnumType(i), file, this, i);
+ }
+
+ this.fields = new FieldDescriptor[proto.getFieldCount()];
+ for (int i = 0; i < proto.getFieldCount(); i++) {
+ this.fields[i] = new FieldDescriptor(
+ proto.getField(i), file, this, i, false);
+ }
+
+ this.extensions = new FieldDescriptor[proto.getExtensionCount()];
+ for (int i = 0; i < proto.getExtensionCount(); i++) {
+ this.extensions[i] = new FieldDescriptor(
+ proto.getExtension(i), file, this, i, true);
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ for (int i = 0; i < nestedTypes.length; i++) {
+ nestedTypes[i].crossLink();
+ }
+
+ for (int i = 0; i < fields.length; i++) {
+ fields[i].crossLink();
+ }
+
+ for (int i = 0; i < extensions.length; i++) {
+ extensions[i].crossLink();
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a field of a message type. */
+ public static final class FieldDescriptor
+ implements GenericDescriptor, Comparable<FieldDescriptor> {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public FieldDescriptorProto toProto() { return proto; }
+
+ /** Get the field's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /** Get the field's number. */
+ public int getNumber() { return proto.getNumber(); }
+
+ /**
+ * Get the field's fully-qualified name.
+ * @see Descriptors.Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /**
+ * Get the field's java type. This is just for convenience. Every
+ * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
+ */
+ public JavaType getJavaType() { return type.getJavaType(); }
+
+ /** Get the {@code FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the field's declared type. */
+ public Type getType() { return type; }
+
+ /** Is this field declared required? */
+ public boolean isRequired() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
+ }
+
+ /** Is this field declared optional? */
+ public boolean isOptional() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
+ }
+
+ /** Is this field declared repeated? */
+ public boolean isRepeated() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
+ }
+
+ /** Returns true if the field had an explicitly-defined default value. */
+ public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
+
+ /**
+ * Returns the field's default value. Valid for all types except for
+ * messages and groups. For all other types, the object returned is of
+ * the same class that would returned by Message.getField(this).
+ */
+ public Object getDefaultValue() {
+ if (getJavaType() == JavaType.MESSAGE) {
+ throw new UnsupportedOperationException(
+ "FieldDescriptor.getDefaultValue() called on an embedded message " +
+ "field.");
+ }
+ return defaultValue;
+ }
+
+ /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
+ public FieldOptions getOptions() { return proto.getOptions(); }
+
+ /** Is this field an extension? */
+ public boolean isExtension() { return proto.hasExtendee(); }
+
+ /**
+ * Get the field's containing type. For extensions, this is the type being
+ * extended, not the location where the extension was defined. See
+ * {@link #getExtensionScope()}.
+ */
+ public Descriptor getContainingType() { return containingType; }
+
+ /**
+ * For extensions defined nested within message types, gets the outer
+ * type. Not valid for non-extension fields. For example, consider
+ * this {@code .proto} file:
+ * <pre>
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ * extend Foo {
+ * optional int32 baz = 1234;
+ * }
+ * message Bar {
+ * extend Foo {
+ * optional int32 qux = 4321;
+ * }
+ * }
+ * </pre>
+ * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
+ * However, {@code baz}'s extension scope is {@code null} while
+ * {@code qux}'s extension scope is {@code Bar}.
+ */
+ public Descriptor getExtensionScope() {
+ if (!isExtension()) {
+ throw new UnsupportedOperationException(
+ "This field is not an extension.");
+ }
+ return extensionScope;
+ }
+
+ /** For embedded message and group fields, gets the field's type. */
+ public Descriptor getMessageType() {
+ if (getJavaType() != JavaType.MESSAGE) {
+ throw new UnsupportedOperationException(
+ "This field is not of message type.");
+ }
+ return messageType;
+ }
+
+ /** For enum fields, gets the field's type. */
+ public EnumDescriptor getEnumType() {
+ if (getJavaType() != JavaType.ENUM) {
+ throw new UnsupportedOperationException(
+ "This field is not of enum type.");
+ }
+ return enumType;
+ }
+
+ /**
+ * Compare with another {@code FieldDescriptor}. This orders fields in
+ * "canonical" order, which simply means ascending order by field number.
+ * {@code other} must be a field of the same type -- i.e.
+ * {@code getContainingType()} must return the same {@code Descriptor} for
+ * both fields.
+ *
+ * @return negative, zero, or positive if {@code this} is less than,
+ * equal to, or greater than {@code other}, respectively.
+ */
+ public int compareTo(FieldDescriptor other) {
+ if (other.containingType != containingType) {
+ throw new IllegalArgumentException(
+ "FieldDescriptors can only be compared to other FieldDescriptors " +
+ "for fields of the same message type.");
+ }
+ return getNumber() - other.getNumber();
+ }
+
+ private final int index;
+
+ private final FieldDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor extensionScope;
+
+ // Possibly initialized during cross-linking.
+ private Type type;
+ private Descriptor containingType;
+ private Descriptor messageType;
+ private EnumDescriptor enumType;
+ private Object defaultValue;
+
+ public static enum Type {
+ DOUBLE (FieldDescriptorProto.Type.TYPE_DOUBLE , JavaType.DOUBLE ),
+ FLOAT (FieldDescriptorProto.Type.TYPE_FLOAT , JavaType.FLOAT ),
+ INT64 (FieldDescriptorProto.Type.TYPE_INT64 , JavaType.LONG ),
+ UINT64 (FieldDescriptorProto.Type.TYPE_UINT64 , JavaType.LONG ),
+ INT32 (FieldDescriptorProto.Type.TYPE_INT32 , JavaType.INT ),
+ FIXED64 (FieldDescriptorProto.Type.TYPE_FIXED64 , JavaType.LONG ),
+ FIXED32 (FieldDescriptorProto.Type.TYPE_FIXED32 , JavaType.INT ),
+ BOOL (FieldDescriptorProto.Type.TYPE_BOOL , JavaType.BOOLEAN ),
+ STRING (FieldDescriptorProto.Type.TYPE_STRING , JavaType.STRING ),
+ GROUP (FieldDescriptorProto.Type.TYPE_GROUP , JavaType.MESSAGE ),
+ MESSAGE (FieldDescriptorProto.Type.TYPE_MESSAGE , JavaType.MESSAGE ),
+ BYTES (FieldDescriptorProto.Type.TYPE_BYTES , JavaType.BYTE_STRING),
+ UINT32 (FieldDescriptorProto.Type.TYPE_UINT32 , JavaType.INT ),
+ ENUM (FieldDescriptorProto.Type.TYPE_ENUM , JavaType.ENUM ),
+ SFIXED32(FieldDescriptorProto.Type.TYPE_SFIXED32, JavaType.INT ),
+ SFIXED64(FieldDescriptorProto.Type.TYPE_SFIXED64, JavaType.LONG ),
+ SINT32 (FieldDescriptorProto.Type.TYPE_SINT32 , JavaType.INT ),
+ SINT64 (FieldDescriptorProto.Type.TYPE_SINT64 , JavaType.LONG );
+
+ private Type(FieldDescriptorProto.Type proto, JavaType javaType) {
+ this.proto = proto;
+ this.javaType = javaType;
+
+ if (this.ordinal() != proto.getNumber() - 1) {
+ throw new RuntimeException(
+ "descriptor.proto changed but Desrciptors.java wasn't updated.");
+ }
+ }
+
+ private FieldDescriptorProto.Type proto;
+ private JavaType javaType;
+
+ public FieldDescriptorProto.Type toProto() { return proto; }
+ public JavaType getJavaType() { return javaType; }
+
+ public static Type valueOf(FieldDescriptorProto.Type type) {
+ return values()[type.getNumber() - 1];
+ }
+ }
+
+ static {
+ // Refuse to init if someone added a new declared type.
+ if (Type.values().length != FieldDescriptorProto.Type.values().length) {
+ throw new RuntimeException(
+ "descriptor.proto has a new declared type but Desrciptors.java " +
+ "wasn't updated.");
+ }
+ }
+
+ public static enum JavaType {
+ INT(0),
+ LONG(0L),
+ FLOAT(0F),
+ DOUBLE(0D),
+ BOOLEAN(false),
+ STRING(""),
+ BYTE_STRING(ByteString.EMPTY),
+ ENUM(null),
+ MESSAGE(null);
+
+ private JavaType(Object defaultDefault) {
+ this.defaultDefault = defaultDefault;
+ }
+
+ /**
+ * The default default value for fields of this type, if it's a primitive
+ * type. This is meant for use inside this file only, hence is private.
+ */
+ private Object defaultDefault;
+ }
+
+ private FieldDescriptor(FieldDescriptorProto proto,
+ FileDescriptor file,
+ Descriptor parent,
+ int index,
+ boolean isExtension)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+
+ if (proto.hasType()) {
+ this.type = Type.valueOf(proto.getType());
+ }
+
+ if (getNumber() <= 0) {
+ throw new DescriptorValidationException(this,
+ "Field numbers must be positive integers.");
+ }
+
+ if (isExtension) {
+ if (!proto.hasExtendee()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.extendee not set for extension field.");
+ }
+ this.containingType = null; // Will be filled in when cross-linking
+ if (parent != null) {
+ this.extensionScope = parent;
+ } else {
+ this.extensionScope = null;
+ }
+ } else {
+ if (proto.hasExtendee()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.extendee set for non-extension field.");
+ }
+ this.containingType = parent;
+ this.extensionScope = null;
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ if (proto.hasExtendee()) {
+ GenericDescriptor extendee =
+ file.pool.lookupSymbol(proto.getExtendee(), this);
+ if (!(extendee instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getExtendee() + "\" is not a message type.");
+ }
+ this.containingType = (Descriptor)extendee;
+
+ if (!getContainingType().isExtensionNumber(getNumber())) {
+ throw new DescriptorValidationException(this,
+ "\"" + getContainingType().getFullName() + "\" does not declare " +
+ getNumber() + " as an extension number.");
+ }
+ }
+
+ if (proto.hasTypeName()) {
+ GenericDescriptor typeDescriptor =
+ file.pool.lookupSymbol(proto.getTypeName(), this);
+
+ if (!proto.hasType()) {
+ // Choose field type based on symbol.
+ if (typeDescriptor instanceof Descriptor) {
+ this.type = Type.MESSAGE;
+ } else if (typeDescriptor instanceof EnumDescriptor) {
+ this.type = Type.ENUM;
+ } else {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getTypeName() + "\" is not a type.");
+ }
+ }
+
+ if (getJavaType() == JavaType.MESSAGE) {
+ if (!(typeDescriptor instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getTypeName() + "\" is not a message type.");
+ }
+ this.messageType = (Descriptor)typeDescriptor;
+
+ if (proto.hasDefaultValue()) {
+ throw new DescriptorValidationException(this,
+ "Messages can't have default values.");
+ }
+ } else if (getJavaType() == JavaType.ENUM) {
+ if (!(typeDescriptor instanceof EnumDescriptor)) {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getTypeName() + "\" is not an enum type.");
+ }
+ this.enumType = (EnumDescriptor)typeDescriptor;
+ } else {
+ throw new DescriptorValidationException(this,
+ "Field with primitive type has type_name.");
+ }
+ } else {
+ if (getJavaType() == JavaType.MESSAGE ||
+ getJavaType() == JavaType.ENUM) {
+ throw new DescriptorValidationException(this,
+ "Field with message or enum type missing type_name.");
+ }
+ }
+
+ // We don't attempt to parse the default value until here because for
+ // enums we need the enum type's descriptor.
+ if (proto.hasDefaultValue()) {
+ if (isRepeated()) {
+ throw new DescriptorValidationException(this,
+ "Repeated fields cannot have default values.");
+ }
+
+ try {
+ switch (getType()) {
+ case INT32:
+ case SINT32:
+ case SFIXED32:
+ defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
+ break;
+ case UINT32:
+ case FIXED32: {
+ defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
+ break;
+ }
+ case INT64:
+ case SINT64:
+ case SFIXED64:
+ defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
+ break;
+ case UINT64:
+ case FIXED64: {
+ defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
+ break;
+ }
+ case FLOAT:
+ defaultValue = Float.valueOf(proto.getDefaultValue());
+ break;
+ case DOUBLE:
+ defaultValue = Double.valueOf(proto.getDefaultValue());
+ break;
+ case BOOL:
+ defaultValue = Boolean.valueOf(proto.getDefaultValue());
+ break;
+ case STRING:
+ defaultValue = proto.getDefaultValue();
+ break;
+ case BYTES:
+ try {
+ defaultValue =
+ TextFormat.unescapeBytes(proto.getDefaultValue());
+ } catch (TextFormat.InvalidEscapeSequence e) {
+ throw new DescriptorValidationException(this,
+ "Couldn't parse default value: " + e.getMessage());
+ }
+ break;
+ case ENUM:
+ defaultValue = enumType.findValueByName(proto.getDefaultValue());
+ if (defaultValue == null) {
+ throw new DescriptorValidationException(this,
+ "Unknown enum default value: \"" +
+ proto.getDefaultValue() + "\"");
+ }
+ break;
+ case MESSAGE:
+ case GROUP:
+ throw new DescriptorValidationException(this,
+ "Message type had default value.");
+ }
+ } catch (NumberFormatException e) {
+ DescriptorValidationException validationException =
+ new DescriptorValidationException(this,
+ "Could not parse default value: \"" +
+ proto.getDefaultValue() + "\"");
+ validationException.initCause(e);
+ throw validationException;
+ }
+ } else {
+ // Determine the default default for this field.
+ if (isRepeated()) {
+ defaultValue = Collections.EMPTY_LIST;
+ } else {
+ switch (getJavaType()) {
+ case ENUM:
+ // We guarantee elsewhere that an enum type always has at least
+ // one possible value.
+ defaultValue = enumType.getValues().get(0);
+ break;
+ case MESSAGE:
+ defaultValue = null;
+ break;
+ default:
+ defaultValue = getJavaType().defaultDefault;
+ break;
+ }
+ }
+ }
+
+ if (!isExtension()) {
+ file.pool.addFieldByNumber(this);
+ }
+
+ if (containingType != null &&
+ containingType.getOptions().getMessageSetWireFormat()) {
+ if (isExtension()) {
+ if (!isOptional() || getType() != Type.MESSAGE) {
+ throw new DescriptorValidationException(this,
+ "Extensions of MessageSets must be optional messages.");
+ }
+ } else {
+ throw new DescriptorValidationException(this,
+ "MessageSets cannot have fields, only extensions.");
+ }
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Describes an enum type. */
+ public static final class EnumDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public EnumDescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name.
+ * @see Descriptors.Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** If this is a nested type, get the outer descriptor, otherwise null. */
+ public Descriptor getContainingType() { return containingType; }
+
+ /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
+ public EnumOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of defined values for this enum. */
+ public List<EnumValueDescriptor> getValues() {
+ return Collections.unmodifiableList(Arrays.asList(values));
+ }
+
+ /**
+ * Find an enum value by name.
+ * @param name The unqualified name of the value (e.g. "FOO").
+ * @return the value's decsriptor, or {@code null} if not found.
+ */
+ public EnumValueDescriptor findValueByName(String name) {
+ GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
+ if (result != null && result instanceof EnumValueDescriptor) {
+ return (EnumValueDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an enum value by number. If multiple enum values have the same
+ * number, this returns the first defined value with that number.
+ * @param number The value's number.
+ * @return the value's decsriptor, or {@code null} if not found.
+ */
+ public EnumValueDescriptor findValueByNumber(int number) {
+ return file.pool.enumValuesByNumber.get(
+ new DescriptorPool.DescriptorIntPair(this, number));
+ }
+
+ private final int index;
+ private final EnumDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor containingType;
+ private EnumValueDescriptor[] values;
+
+ private EnumDescriptor(EnumDescriptorProto proto,
+ FileDescriptor file,
+ Descriptor parent,
+ int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+ this.containingType = parent;
+
+ if (proto.getValueCount() == 0) {
+ // We cannot allow enums with no values because this would mean there
+ // would be no valid default value for fields of this type.
+ throw new DescriptorValidationException(this,
+ "Enums must contain at least one value.");
+ }
+
+ values = new EnumValueDescriptor[proto.getValueCount()];
+ for (int i = 0; i < proto.getValueCount(); i++) {
+ this.values[i] = new EnumValueDescriptor(
+ proto.getValue(i), file, this, i);
+ }
+
+ file.pool.addSymbol(this);
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Describes one value within an enum type. Note that multiple defined
+ * values may have the same number. In generated Java code, all values
+ * with the same number after the first become aliases of the first.
+ * However, they still have independent EnumValueDescriptors.
+ */
+ public static final class EnumValueDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public EnumValueDescriptorProto toProto() { return proto; }
+
+ /** Get the value's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /** Get the value's number. */
+ public int getNumber() { return proto.getNumber(); }
+
+ /**
+ * Get the value's fully-qualified name.
+ * @see Descriptors.Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the value's enum type. */
+ public EnumDescriptor getType() { return type; }
+
+ /**
+ * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
+ */
+ public EnumValueOptions getOptions() { return proto.getOptions(); }
+
+ private final int index;
+ private final EnumValueDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final EnumDescriptor type;
+
+ private EnumValueDescriptor(EnumValueDescriptorProto proto,
+ FileDescriptor file,
+ EnumDescriptor parent,
+ int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.file = file;
+ this.type = parent;
+
+ this.fullName = parent.getFullName() + "." + proto.getName();
+
+ file.pool.addSymbol(this);
+ file.pool.addEnumValueByNumber(this);
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a service type. */
+ public static final class ServiceDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public ServiceDescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name.
+ * @see Descriptors.Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
+ public ServiceOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of methods for this service. */
+ public List<MethodDescriptor> getMethods() {
+ return Collections.unmodifiableList(Arrays.asList(methods));
+ }
+
+ /**
+ * Find a method by name.
+ * @param name The unqualified name of the method (e.g. "Foo").
+ * @return the method's decsriptor, or {@code null} if not found.
+ */
+ public MethodDescriptor findMethodByName(String name) {
+ GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
+ if (result != null && result instanceof MethodDescriptor) {
+ return (MethodDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ private final int index;
+ private final ServiceDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private MethodDescriptor[] methods;
+
+ private ServiceDescriptor(ServiceDescriptorProto proto,
+ FileDescriptor file,
+ int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.fullName = computeFullName(file, null, proto.getName());
+ this.file = file;
+
+ this.methods = new MethodDescriptor[proto.getMethodCount()];
+ for (int i = 0; i < proto.getMethodCount(); i++) {
+ this.methods[i] = new MethodDescriptor(
+ proto.getMethod(i), file, this, i);
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ private void crossLink() throws DescriptorValidationException {
+ for (int i = 0; i < methods.length; i++) {
+ methods[i].crossLink();
+ }
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Describes one method within a service type.
+ */
+ public static final class MethodDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public MethodDescriptorProto toProto() { return proto; }
+
+ /** Get the method's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the method's fully-qualified name.
+ * @see Descriptors.Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the method's service type. */
+ public ServiceDescriptor getService() { return service; }
+
+ /** Get the method's input type. */
+ public Descriptor getInputType() { return inputType; }
+
+ /** Get the method's output type. */
+ public Descriptor getOutputType() { return outputType; }
+
+ /**
+ * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
+ */
+ public MethodOptions getOptions() { return proto.getOptions(); }
+
+ private final int index;
+ private final MethodDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final ServiceDescriptor service;
+
+ // Initialized during cross-linking.
+ private Descriptor inputType;
+ private Descriptor outputType;
+
+ private MethodDescriptor(MethodDescriptorProto proto,
+ FileDescriptor file,
+ ServiceDescriptor parent,
+ int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.file = file;
+ this.service = parent;
+
+ this.fullName = parent.getFullName() + "." + proto.getName();
+
+ file.pool.addSymbol(this);
+ }
+
+ private void crossLink() throws DescriptorValidationException {
+ GenericDescriptor inputType =
+ file.pool.lookupSymbol(proto.getInputType(), this);
+ if (!(inputType instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getInputType() + "\" is not a message type.");
+ }
+ this.inputType = (Descriptor)inputType;
+
+ GenericDescriptor outputType =
+ file.pool.lookupSymbol(proto.getOutputType(), this);
+ if (!(outputType instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ "\"" + proto.getOutputType() + "\" is not a message type.");
+ }
+ this.outputType = (Descriptor)outputType;
+ }
+ }
+
+ // =================================================================
+
+ private static String computeFullName(FileDescriptor file,
+ Descriptor parent,
+ String name) {
+ if (parent != null) {
+ return parent.getFullName() + "." + name;
+ } else if (file.getPackage().length() > 0) {
+ return file.getPackage() + "." + name;
+ } else {
+ return name;
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * All descriptors except {@code FileDescriptor} implement this to make
+ * {@code DescriptorPool}'s life easier.
+ */
+ private static interface GenericDescriptor {
+ Message toProto();
+ String getName();
+ String getFullName();
+ FileDescriptor getFile();
+ }
+
+ /**
+ * Thrown when building descriptors fails because the source DescriptorProtos
+ * are not valid.
+ */
+ public static class DescriptorValidationException extends Exception {
+ /** Gets the full name of the descriptor where the error occurred. */
+ public String getProblemSymbolName() { return name; }
+
+ /**
+ * Gets the the protocol message representation of the invalid descriptor.
+ */
+ public Message getProblemProto() { return proto; }
+
+ /**
+ * Gets a human-readable description of the error.
+ */
+ public String getDescription() { return description; }
+
+ private final String name;
+ private final Message proto;
+ private final String description;
+
+ private DescriptorValidationException(GenericDescriptor problemDescriptor,
+ String description) {
+ super(problemDescriptor.getFullName() + ": " + description);
+
+ // Note that problemDescriptor may be partially uninitialized, so we
+ // don't want to expose it directly to the user. So, we only provide
+ // the name and the original proto.
+ this.name = problemDescriptor.getFullName();
+ this.proto = problemDescriptor.toProto();
+ this.description = description;
+ }
+
+ private DescriptorValidationException(FileDescriptor problemDescriptor,
+ String description) {
+ super(problemDescriptor.getName() + ": " + description);
+
+ // Note that problemDescriptor may be partially uninitialized, so we
+ // don't want to expose it directly to the user. So, we only provide
+ // the name and the original proto.
+ this.name = problemDescriptor.getName();
+ this.proto = problemDescriptor.toProto();
+ this.description = description;
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * A private helper class which contains lookup tables containing all the
+ * descriptors defined in a particular file.
+ */
+ private static final class DescriptorPool {
+ DescriptorPool(FileDescriptor[] dependencies) {
+ this.dependencies = new DescriptorPool[dependencies.length];
+
+ for (int i = 0; i < dependencies.length; i++) {
+ this.dependencies[i] = dependencies[i].pool;
+ }
+
+ for (int i = 0; i < dependencies.length; i++) {
+ try {
+ addPackage(dependencies[i].getPackage(), dependencies[i]);
+ } catch (DescriptorValidationException e) {
+ // Can't happen, because addPackage() only fails when the name
+ // conflicts with a non-package, but we have not yet added any
+ // non-packages at this point.
+ assert false;
+ }
+ }
+ }
+
+ final DescriptorPool[] dependencies;
+
+ final Map<String, GenericDescriptor> descriptorsByName =
+ new HashMap<String, GenericDescriptor>();
+ final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
+ new HashMap<DescriptorIntPair, FieldDescriptor>();
+ final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
+ new HashMap<DescriptorIntPair, EnumValueDescriptor>();
+
+ /** Find a generic descriptor by fully-qualified name. */
+ GenericDescriptor findSymbol(String fullName) {
+ GenericDescriptor result = descriptorsByName.get(fullName);
+ if (result != null) return result;
+
+ for (int i = 0; i < dependencies.length; i++) {
+ result = dependencies[i].descriptorsByName.get(fullName);
+ if (result != null) return result;
+ }
+
+ return null;
+ }
+
+ /**
+ * Look up a descriptor by name, relative to some other descriptor.
+ * The name may be fully-qualified (with a leading '.'),
+ * partially-qualified, or unqualified. C++-like name lookup semantics
+ * are used to search for the matching descriptor.
+ */
+ GenericDescriptor lookupSymbol(String name,
+ GenericDescriptor relativeTo)
+ throws DescriptorValidationException {
+ // TODO(kenton): This could be optimized in a number of ways.
+
+ GenericDescriptor result;
+ if (name.startsWith(".")) {
+ // Fully-qualified name.
+ result = findSymbol(name.substring(1));
+ } else {
+ // If "name" is a compound identifier, we want to search for the
+ // first component of it, then search within it for the rest.
+ int firstPartLength = name.indexOf('.');
+ String firstPart;
+ if (firstPartLength == -1) {
+ firstPart = name;
+ } else {
+ firstPart = name.substring(0, firstPartLength);
+ }
+
+ // We will search each parent scope of "relativeTo" looking for the
+ // symbol.
+ StringBuilder scopeToTry = new StringBuilder(relativeTo.getFullName());
+
+ while (true) {
+ // Chop off the last component of the scope.
+ int dotpos = scopeToTry.lastIndexOf(".");
+ if (dotpos == -1) {
+ result = findSymbol(name);
+ break;
+ } else {
+ scopeToTry.setLength(dotpos + 1);
+
+ // Append firstPart and try to find.
+ scopeToTry.append(firstPart);
+ result = findSymbol(scopeToTry.toString());
+
+ if (result != null) {
+ if (firstPartLength != -1) {
+ // We only found the first part of the symbol. Now look for
+ // the whole thing. If this fails, we *don't* want to keep
+ // searching parent scopes.
+ scopeToTry.setLength(dotpos + 1);
+ scopeToTry.append(name);
+ result = findSymbol(scopeToTry.toString());
+ }
+ break;
+ }
+
+ // Not found. Remove the name so we can try again.
+ scopeToTry.setLength(dotpos);
+ }
+ }
+ }
+
+ if (result == null) {
+ throw new DescriptorValidationException(relativeTo,
+ "\"" + name + "\" is not defined.");
+ } else {
+ return result;
+ }
+ }
+
+ /**
+ * Adds a symbol to the symbol table. If a symbol with the same name
+ * already exists, throws an error.
+ */
+ void addSymbol(GenericDescriptor descriptor)
+ throws DescriptorValidationException {
+ validateSymbolName(descriptor);
+
+ String fullName = descriptor.getFullName();
+ int dotpos = fullName.lastIndexOf('.');
+
+ GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
+ if (old != null) {
+ descriptorsByName.put(fullName, old);
+
+ if (descriptor.getFile() == old.getFile()) {
+ if (dotpos == -1) {
+ throw new DescriptorValidationException(descriptor,
+ "\"" + fullName + "\" is already defined.");
+ } else {
+ throw new DescriptorValidationException(descriptor,
+ "\"" + fullName.substring(dotpos + 1) +
+ "\" is already defined in \"" +
+ fullName.substring(0, dotpos) + "\".");
+ }
+ } else {
+ throw new DescriptorValidationException(descriptor,
+ "\"" + fullName + "\" is already defined in file \"" +
+ old.getFile().getName() + "\".");
+ }
+ }
+ }
+
+ /**
+ * Represents a package in the symbol table. We use PackageDescriptors
+ * just as placeholders so that someone cannot define, say, a message type
+ * that has the same name as an existing package.
+ */
+ static final class PackageDescriptor implements GenericDescriptor {
+ public Message toProto() { return file.toProto(); }
+ public String getName() { return name; }
+ public String getFullName() { return fullName; }
+ public FileDescriptor getFile() { return file; }
+
+ PackageDescriptor(String name, String fullName, FileDescriptor file) {
+ this.file = file;
+ this.fullName = fullName;
+ this.name = name;
+ }
+
+ String name;
+ String fullName;
+ FileDescriptor file;
+ }
+
+ /**
+ * Adds a package to the symbol tables. If a package by the same name
+ * already exists, that is fine, but if some other kind of symbol exists
+ * under the same name, an exception is thrown. If the package has
+ * multiple components, this also adds the parent package(s).
+ */
+ void addPackage(String fullName, FileDescriptor file)
+ throws DescriptorValidationException {
+ int dotpos = fullName.lastIndexOf('.');
+ String name;
+ if (dotpos != -1) {
+ addPackage(fullName.substring(0, dotpos), file);
+ name = fullName.substring(dotpos + 1);
+ } else {
+ name = fullName;
+ }
+
+ GenericDescriptor old =
+ descriptorsByName.put(fullName,
+ new PackageDescriptor(fullName, name, file));
+ if (old != null) {
+ descriptorsByName.put(fullName, old);
+ if (!(old instanceof PackageDescriptor)) {
+ throw new DescriptorValidationException(file,
+ "\"" + name + "\" is already defined (as something other than a " +
+ "package) in file \"" + old.getFile().getName() + "\".");
+ }
+ }
+ }
+
+ /** A (GenericDescriptor, int) pair, used as a map key. */
+ static final class DescriptorIntPair {
+ final GenericDescriptor descriptor;
+ final int number;
+
+ DescriptorIntPair(GenericDescriptor descriptor, int number) {
+ this.descriptor = descriptor;
+ this.number = number;
+ }
+
+ public int hashCode() {
+ return descriptor.hashCode() * ((1 << 16) - 1) + number;
+ }
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DescriptorIntPair)) return false;
+ DescriptorIntPair other = (DescriptorIntPair)obj;
+ return descriptor == other.descriptor && number == other.number;
+ }
+ }
+
+ /**
+ * Adds a field to the fieldsByNumber table. Throws an exception if a
+ * field with hte same containing type and number already exists.
+ */
+ void addFieldByNumber(FieldDescriptor field)
+ throws DescriptorValidationException {
+ DescriptorIntPair key =
+ new DescriptorIntPair(field.getContainingType(), field.getNumber());
+ FieldDescriptor old = fieldsByNumber.put(key, field);
+ if (old != null) {
+ fieldsByNumber.put(key, old);
+ throw new DescriptorValidationException(field,
+ "Field number " + field.getNumber() +
+ "has already been used in \"" +
+ field.getContainingType().getFullName() +
+ "\" by field \"" + old.getName() + "\".");
+ }
+ }
+
+ /**
+ * Adds an enum value to the enumValuesByNumber table. If an enum value
+ * with the same type and number already exists, does nothing. (This is
+ * allowed; the first value define with the number takes precedence.)
+ */
+ void addEnumValueByNumber(EnumValueDescriptor value) {
+ DescriptorIntPair key =
+ new DescriptorIntPair(value.getType(), value.getNumber());
+ EnumValueDescriptor old = enumValuesByNumber.put(key, value);
+ if (old != null) {
+ enumValuesByNumber.put(key, old);
+ // Not an error: Multiple enum values may have the same number, but
+ // we only want the first one in the map.
+ }
+ }
+
+ /**
+ * Verifies that the descriptor's name is valid (i.e. it contains only
+ * letters, digits, and underscores, and does not start with a digit).
+ */
+ void validateSymbolName(GenericDescriptor descriptor)
+ throws DescriptorValidationException {
+ String name = descriptor.getName();
+ if (name.length() == 0) {
+ throw new DescriptorValidationException(descriptor, "Missing name.");
+ } else {
+ boolean valid = true;
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ // Non-ASCII characters are not valid in protobuf identifiers, even
+ // if they are letters or digits.
+ if (c >= 128) {
+ valid = false;
+ }
+ // First character must be letter or _. Subsequent characters may
+ // be letters, numbers, or digits.
+ if (Character.isLetter(c) || c == '_' ||
+ (Character.isDigit(c) && i > 0)) {
+ // Valid
+ } else {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ throw new DescriptorValidationException(descriptor,
+ "\"" + name + "\" is not a valid identifier.");
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java
new file mode 100644
index 00000000..d9a39f0e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -0,0 +1,391 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * An implementation of {@link Message} that can represent arbitrary types,
+ * given a {@link Descriptors.Descriptor}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class DynamicMessage extends AbstractMessage {
+ private final Descriptor type;
+ private final FieldSet fields;
+ private final UnknownFieldSet unknownFields;
+ private int memoizedSize = -1;
+
+ /**
+ * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
+ */
+ private DynamicMessage(Descriptor type, FieldSet fields,
+ UnknownFieldSet unknownFields) {
+ this.type = type;
+ this.fields = fields;
+ this.unknownFields = unknownFields;
+ }
+
+ /**
+ * Get a {@code DynamicMessage} representing the default instance of the
+ * given type.
+ */
+ public static DynamicMessage getDefaultInstance(Descriptor type) {
+ return new DynamicMessage(type, FieldSet.emptySet(),
+ UnknownFieldSet.getDefaultInstance());
+ }
+
+ /** Parse a message of the given type from the given input stream. */
+ public static DynamicMessage parseFrom(Descriptor type,
+ CodedInputStream input)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input).buildParsed();
+ }
+
+ /** Parse a message of the given type from the given input stream. */
+ public static DynamicMessage parseFrom(
+ Descriptor type,
+ CodedInputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, ByteString data)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, ByteString data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, byte[] data)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, byte[] data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+ }
+
+ /** Parse a message of the given type from {@code input} and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, InputStream input)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input).buildParsed();
+ }
+
+ /** Parse a message of the given type from {@code input} and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, InputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+ }
+
+ /** Construct a {@link Message.Builder} for the given type. */
+ public static Builder newBuilder(Descriptor type) {
+ return new Builder(type);
+ }
+
+ /**
+ * Construct a {@link Message.Builder} for a message of the same type as
+ * {@code prototype}, and initialize it with {@code prototype}'s contents.
+ */
+ public static Builder newBuilder(Message prototype) {
+ return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
+ }
+
+ // -----------------------------------------------------------------
+ // Implementation of Message interface.
+
+ public Descriptor getDescriptorForType() {
+ return type;
+ }
+
+ public DynamicMessage getDefaultInstanceForType() {
+ return getDefaultInstance(type);
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return fields.getAllFields();
+ }
+
+ public boolean hasField(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.hasField(field);
+ }
+
+ public Object getField(FieldDescriptor field) {
+ verifyContainingType(field);
+ Object result = fields.getField(field);
+ if (result == null) {
+ result = getDefaultInstance(field.getMessageType());
+ }
+ return result;
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ verifyContainingType(field);
+ return fields.getRepeatedField(field, index);
+ }
+
+ public UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ public boolean isInitialized() {
+ return fields.isInitialized(type);
+ }
+
+ public void writeTo(CodedOutputStream output) throws IOException {
+ fields.writeTo(output);
+ if (type.getOptions().getMessageSetWireFormat()) {
+ unknownFields.writeAsMessageSetTo(output);
+ } else {
+ unknownFields.writeTo(output);
+ }
+ }
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ size = fields.getSerializedSize();
+ if (type.getOptions().getMessageSetWireFormat()) {
+ size += unknownFields.getSerializedSizeAsMessageSet();
+ } else {
+ size += unknownFields.getSerializedSize();
+ }
+
+ memoizedSize = size;
+ return size;
+ }
+
+ public Builder newBuilderForType() {
+ return new Builder(type);
+ }
+
+ /** Verifies that the field is a field of this message. */
+ private void verifyContainingType(FieldDescriptor field) {
+ if (field.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Builder for {@link DynamicMessage}s.
+ */
+ public static final class Builder extends AbstractMessage.Builder<Builder> {
+ private final Descriptor type;
+ private FieldSet fields;
+ private UnknownFieldSet unknownFields;
+
+ /** Construct a {@code Builder} for the given type. */
+ private Builder(Descriptor type) {
+ this.type = type;
+ this.fields = FieldSet.newFieldSet();
+ this.unknownFields = UnknownFieldSet.getDefaultInstance();
+ }
+
+ // ---------------------------------------------------------------
+ // Implementation of Message.Builder interface.
+
+ public Builder clear() {
+ fields.clear();
+ return this;
+ }
+
+ public Builder mergeFrom(Message other) {
+ if (other.getDescriptorForType() != type) {
+ throw new IllegalArgumentException(
+ "mergeFrom(Message) can only merge messages of the same type.");
+ }
+
+ fields.mergeFrom(other);
+ return this;
+ }
+
+ public DynamicMessage build() {
+ if (!isInitialized()) {
+ throw new UninitializedMessageException(
+ new DynamicMessage(type, fields, unknownFields));
+ }
+ return buildPartial();
+ }
+
+ /**
+ * Helper for DynamicMessage.parseFrom() methods to call. Throws
+ * {@link InvalidProtocolBufferException} instead of
+ * {@link UninitializedMessageException}.
+ */
+ private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw new UninitializedMessageException(
+ new DynamicMessage(type, fields, unknownFields))
+ .asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ public DynamicMessage buildPartial() {
+ fields.makeImmutable();
+ DynamicMessage result =
+ new DynamicMessage(type, fields, unknownFields);
+ fields = null;
+ unknownFields = null;
+ return result;
+ }
+
+ public Builder clone() {
+ Builder result = new Builder(type);
+ result.fields.mergeFrom(fields);
+ return result;
+ }
+
+ public boolean isInitialized() {
+ return fields.isInitialized(type);
+ }
+
+ public Builder mergeFrom(CodedInputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ UnknownFieldSet.Builder unknownFieldsBuilder =
+ UnknownFieldSet.newBuilder(unknownFields);
+ fields.mergeFrom(input, unknownFieldsBuilder, extensionRegistry, this);
+ unknownFields = unknownFieldsBuilder.build();
+ return this;
+ }
+
+ public Descriptor getDescriptorForType() {
+ return type;
+ }
+
+ public DynamicMessage getDefaultInstanceForType() {
+ return getDefaultInstance(type);
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return fields.getAllFields();
+ }
+
+ public Builder newBuilderForField(FieldDescriptor field) {
+ verifyContainingType(field);
+
+ if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "newBuilderForField is only valid for fields with message type.");
+ }
+
+ return new Builder(field.getMessageType());
+ }
+
+ public boolean hasField(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.hasField(field);
+ }
+
+ public Object getField(FieldDescriptor field) {
+ verifyContainingType(field);
+ Object result = fields.getField(field);
+ if (result == null) {
+ result = getDefaultInstance(field.getMessageType());
+ }
+ return result;
+ }
+
+ public Builder setField(FieldDescriptor field, Object value) {
+ verifyContainingType(field);
+ fields.setField(field, value);
+ return this;
+ }
+
+ public Builder clearField(FieldDescriptor field) {
+ verifyContainingType(field);
+ fields.clearField(field);
+ return this;
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ verifyContainingType(field);
+ return fields.getRepeatedField(field, index);
+ }
+
+ public Builder setRepeatedField(FieldDescriptor field,
+ int index, Object value) {
+ verifyContainingType(field);
+ fields.setRepeatedField(field, index, value);
+ return this;
+ }
+
+ public Builder addRepeatedField(FieldDescriptor field, Object value) {
+ verifyContainingType(field);
+ fields.addRepeatedField(field, value);
+ return this;
+ }
+
+ public UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+ this.unknownFields = unknownFields;
+ return this;
+ }
+
+ public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
+ this.unknownFields =
+ UnknownFieldSet.newBuilder(this.unknownFields)
+ .mergeFrom(unknownFields)
+ .build();
+ return this;
+ }
+
+ /** Verifies that the field is a field of this message. */
+ private void verifyContainingType(FieldDescriptor field) {
+ if (field.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
new file mode 100644
index 00000000..6954b3b6
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -0,0 +1,237 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A table of known extensions, searchable by name or field number. When
+ * parsing a protocol message that might have extensions, you must provide
+ * an {@code ExtensionRegistry} in which you have registered any extensions
+ * that you want to be able to parse. Otherwise, those extensions will just
+ * be treated like unknown fields.
+ *
+ * <p>For example, if you had the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * Then you might write code like:
+ *
+ * <pre>
+ * ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ * registry.add(MyProto.bar);
+ * MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
+ * </pre>
+ *
+ * <p>Background:
+ *
+ * <p>You might wonder why this is necessary. Two alternatives might come to
+ * mind. First, you might imagine a system where generated extensions are
+ * automatically registered when their containing classes are loaded. This
+ * is a popular technique, but is bad design; among other things, it creates a
+ * situation where behavior can change depending on what classes happen to be
+ * loaded. It also introduces a security vulnerability, because an
+ * unprivileged class could cause its code to be called unexpectedly from a
+ * privileged class by registering itself as an extension of the right type.
+ *
+ * <p>Another option you might consider is lazy parsing: do not parse an
+ * extension until it is first requested, at which point the caller must
+ * provide a type to use. This introduces a different set of problems. First,
+ * it would require a mutex lock any time an extension was accessed, which
+ * would be slow. Second, corrupt data would not be detected until first
+ * access, at which point it would be much harder to deal with it. Third, it
+ * could violate the expectation that message objects are immutable, since the
+ * type provided could be any arbitrary message class. An unpriviledged user
+ * could take advantage of this to inject a mutable object into a message
+ * belonging to priviledged code and create mischief.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class ExtensionRegistry {
+ /** Construct a new, empty instance. */
+ public static ExtensionRegistry newInstance() {
+ return new ExtensionRegistry(
+ new HashMap<String, ExtensionInfo>(),
+ new HashMap<DescriptorIntPair, ExtensionInfo>());
+ }
+
+ /** Get the unmodifiable singleton empty instance. */
+ public static ExtensionRegistry getEmptyRegistry() {
+ return EMPTY;
+ }
+
+ /** Returns an unmodifiable view of the registry. */
+ public ExtensionRegistry getUnmodifiable() {
+ return new ExtensionRegistry(
+ Collections.unmodifiableMap(extensionsByName),
+ Collections.unmodifiableMap(extensionsByNumber));
+ }
+
+ /** A (Descriptor, Message) pair, returned by lookup methods. */
+ public static final class ExtensionInfo {
+ /** The extension's descriptor. */
+ public final FieldDescriptor descriptor;
+
+ /**
+ * A default instance of the extension's type, if it has a message type.
+ * Otherwise, {@code null}.
+ */
+ public final Message defaultInstance;
+
+ private ExtensionInfo(FieldDescriptor descriptor) {
+ this.descriptor = descriptor;
+ this.defaultInstance = null;
+ }
+ private ExtensionInfo(FieldDescriptor descriptor, Message defaultInstance) {
+ this.descriptor = descriptor;
+ this.defaultInstance = defaultInstance;
+ }
+ }
+
+ /**
+ * Find an extension by fully-qualified field name, in the proto namespace.
+ * I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
+ * a match is found.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findExtensionByName(String fullName) {
+ return extensionsByName.get(fullName);
+ }
+
+ /**
+ * Find an extension by containing type and field number.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findExtensionByNumber(Descriptor containingType,
+ int fieldNumber) {
+ return extensionsByNumber.get(
+ new DescriptorIntPair(containingType, fieldNumber));
+ }
+
+ /** Add an extension from a generated file to the registry. */
+ public void add(GeneratedMessage.GeneratedExtension<?, ?> extension) {
+ if (extension.getDescriptor().getJavaType() ==
+ FieldDescriptor.JavaType.MESSAGE) {
+ add(new ExtensionInfo(extension.getDescriptor(),
+ extension.getMessageDefaultInstance()));
+ } else {
+ add(new ExtensionInfo(extension.getDescriptor(), null));
+ }
+ }
+
+ /** Add a non-message-type extension to the registry by descriptor. */
+ public void add(FieldDescriptor type) {
+ if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() must be provided a default instance when " +
+ "adding an embedded message extension.");
+ }
+ add(new ExtensionInfo(type, null));
+ }
+
+ /** Add a message-type extension to the registry by descriptor. */
+ public void add(FieldDescriptor type, Message defaultInstance) {
+ if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() provided a default instance for a " +
+ "non-message extension.");
+ }
+ add(new ExtensionInfo(type, defaultInstance));
+ }
+
+ // =================================================================
+ // Private stuff.
+
+ private ExtensionRegistry(
+ Map<String, ExtensionInfo> extensionsByName,
+ Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber) {
+ this.extensionsByName = extensionsByName;
+ this.extensionsByNumber = extensionsByNumber;
+ }
+
+ private final Map<String, ExtensionInfo> extensionsByName;
+ private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+
+ private static final ExtensionRegistry EMPTY =
+ new ExtensionRegistry(
+ Collections.<String, ExtensionInfo>emptyMap(),
+ Collections.<DescriptorIntPair, ExtensionInfo>emptyMap());
+
+ private void add(ExtensionInfo extension) {
+ if (!extension.descriptor.isExtension()) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
+ "(non-extension) field.");
+ }
+
+ extensionsByName.put(extension.descriptor.getFullName(), extension);
+ extensionsByNumber.put(
+ new DescriptorIntPair(extension.descriptor.getContainingType(),
+ extension.descriptor.getNumber()),
+ extension);
+
+ FieldDescriptor field = extension.descriptor;
+ if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
+ field.getType() == FieldDescriptor.Type.MESSAGE &&
+ field.isOptional() &&
+ field.getExtensionScope() == field.getMessageType()) {
+ // This is an extension of a MessageSet type defined within the extension
+ // type's own scope. For backwards-compatibility, allow it to be looked
+ // up by type name.
+ extensionsByName.put(field.getMessageType().getFullName(), extension);
+ }
+ }
+
+ /** A (GenericDescriptor, int) pair, used as a map key. */
+ private static final class DescriptorIntPair {
+ final Descriptor descriptor;
+ final int number;
+
+ DescriptorIntPair(Descriptor descriptor, int number) {
+ this.descriptor = descriptor;
+ this.number = number;
+ }
+
+ public int hashCode() {
+ return descriptor.hashCode() * ((1 << 16) - 1) + number;
+ }
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DescriptorIntPair)) return false;
+ DescriptorIntPair other = (DescriptorIntPair)obj;
+ return descriptor == other.descriptor && number == other.number;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java
new file mode 100644
index 00000000..3a5dc488
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/FieldSet.java
@@ -0,0 +1,662 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A class which represents an arbitrary set of fields of some message type.
+ * This is used to implement {@link DynamicMessage}, and also to represent
+ * extensions in {@link GeneratedMessage}. This class is package-private,
+ * since outside users should probably be using {@link DynamicMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+final class FieldSet {
+ private Map<FieldDescriptor, Object> fields;
+
+ /** Construct a new FieldSet. */
+ private FieldSet() {
+ // Use a TreeMap because fields need to be in canonical order when
+ // serializing.
+ this.fields = new TreeMap<FieldDescriptor, Object>();
+ }
+
+ /**
+ * Construct a new FieldSet with the given map. This is only used by
+ * DEFAULT_INSTANCE, to pass in an immutable empty map.
+ */
+ private FieldSet(Map<FieldDescriptor, Object> fields) {
+ this.fields = fields;
+ }
+
+ /** Construct a new FieldSet. */
+ public static FieldSet newFieldSet() {
+ return new FieldSet();
+ }
+
+ /** Get an immutable empty FieldSet. */
+ public static FieldSet emptySet() {
+ return DEFAULT_INSTANCE;
+ }
+ private static final FieldSet DEFAULT_INSTANCE =
+ new FieldSet(Collections.<FieldDescriptor, Object>emptyMap());
+
+ /** Make this FieldSet immutable from this point forward. */
+ @SuppressWarnings("unchecked")
+ public void makeImmutable() {
+ for (Map.Entry<FieldDescriptor, Object> entry: fields.entrySet()) {
+ if (entry.getKey().isRepeated()) {
+ List value = (List)entry.getValue();
+ entry.setValue(Collections.unmodifiableList(value));
+ }
+ }
+ fields = Collections.unmodifiableMap(fields);
+ }
+
+ // =================================================================
+
+ /** See {@link Message.Builder#clear()}. */
+ public void clear() {
+ fields.clear();
+ }
+
+ /** See {@link Message#getAllFields()}. */
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return Collections.unmodifiableMap(fields);
+ }
+
+ /**
+ * Get an interator to the field map. This iterator should not be leaked
+ * out of the protobuf library as it is not protected from mutation.
+ */
+ public Iterator<Map.Entry<Descriptors.FieldDescriptor, Object>> iterator() {
+ return fields.entrySet().iterator();
+ }
+
+ /** See {@link Message#hasField(Descriptors.FieldDescriptor)}. */
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ if (field.isRepeated()) {
+ throw new IllegalArgumentException(
+ "hasField() can only be called on non-repeated fields.");
+ }
+
+ return fields.containsKey(field);
+ }
+
+ /**
+ * See {@link Message#getField(Descriptors.FieldDescriptor)}. This method
+ * returns {@code null} if the field is a singular message type and is not
+ * set; in this case it is up to the caller to fetch the message's default
+ * instance.
+ */
+ public Object getField(Descriptors.FieldDescriptor field) {
+ Object result = fields.get(field);
+ if (result == null) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ return Collections.emptyList();
+ } else {
+ return null;
+ }
+ } else {
+ return field.getDefaultValue();
+ }
+ } else {
+ return result;
+ }
+ }
+
+ /** See {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}. */
+ @SuppressWarnings("unchecked")
+ public void setField(Descriptors.FieldDescriptor field, Object value) {
+ if (field.isRepeated()) {
+ if (!(value instanceof List)) {
+ throw new IllegalArgumentException(
+ "Wrong object type used with protocol message reflection.");
+ }
+
+ // Wrap the contents in a new list so that the caller cannot change
+ // the list's contents after setting it.
+ List newList = new ArrayList();
+ newList.addAll((List)value);
+ for (Object element : newList) {
+ verifyType(field, element);
+ }
+ value = newList;
+ } else {
+ verifyType(field, value);
+ }
+
+ fields.put(field, value);
+ }
+
+ /** See {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
+ public void clearField(Descriptors.FieldDescriptor field) {
+ fields.remove(field);
+ }
+
+ /** See {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ if (!field.isRepeated()) {
+ throw new IllegalArgumentException(
+ "getRepeatedFieldCount() can only be called on repeated fields.");
+ }
+
+ return ((List)getField(field)).size();
+ }
+
+ /** See {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
+ public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
+ if (!field.isRepeated()) {
+ throw new IllegalArgumentException(
+ "getRepeatedField() can only be called on repeated fields.");
+ }
+
+ return ((List)getField(field)).get(index);
+ }
+
+ /** See {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}. */
+ @SuppressWarnings("unchecked")
+ public void setRepeatedField(Descriptors.FieldDescriptor field, int index,
+ Object value) {
+ if (!field.isRepeated()) {
+ throw new IllegalArgumentException(
+ "setRepeatedField() can only be called on repeated fields.");
+ }
+
+ verifyType(field, value);
+
+ List list = (List)fields.get(field);
+ if (list == null) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ list.set(index, value);
+ }
+
+ /** See {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}. */
+ @SuppressWarnings("unchecked")
+ public void addRepeatedField(Descriptors.FieldDescriptor field,
+ Object value) {
+ if (!field.isRepeated()) {
+ throw new IllegalArgumentException(
+ "setRepeatedField() can only be called on repeated fields.");
+ }
+
+ verifyType(field, value);
+
+ List list = (List)fields.get(field);
+ if (list == null) {
+ list = new ArrayList();
+ fields.put(field, list);
+ }
+
+ list.add(value);
+ }
+
+ /**
+ * Verifies that the given object is of the correct type to be a valid
+ * value for the given field. (For repeated fields, this checks if the
+ * object is the right type to be one element of the field.)
+ *
+ * @throws IllegalArgumentException The value is not of the right type.
+ */
+ private void verifyType(FieldDescriptor field, Object value) {
+ boolean isValid = false;
+ switch (field.getJavaType()) {
+ case INT: isValid = value instanceof Integer ; break;
+ case LONG: isValid = value instanceof Long ; break;
+ case FLOAT: isValid = value instanceof Float ; break;
+ case DOUBLE: isValid = value instanceof Double ; break;
+ case BOOLEAN: isValid = value instanceof Boolean ; break;
+ case STRING: isValid = value instanceof String ; break;
+ case BYTE_STRING: isValid = value instanceof ByteString; break;
+ case ENUM:
+ isValid = value instanceof EnumValueDescriptor &&
+ ((EnumValueDescriptor)value).getType() == field.getEnumType();
+ break;
+ case MESSAGE:
+ isValid = value instanceof Message &&
+ ((Message)value).getDescriptorForType() == field.getMessageType();
+ break;
+ }
+
+ if (!isValid) {
+ // When chaining calls to setField(), it can be hard to tell from
+ // the stack trace which exact call failed, since the whole chain is
+ // considered one line of code. So, let's make sure to include the
+ // field name and other useful info in the exception.
+ throw new IllegalArgumentException(
+ "Wrong object type used with protocol message reflection. " +
+ "Message type \"" + field.getContainingType().getFullName() +
+ "\", field \"" +
+ (field.isExtension() ? field.getFullName() : field.getName()) +
+ "\", value was type \"" + value.getClass().getName() + "\".");
+ }
+ }
+
+ // =================================================================
+ // Parsing and serialization
+
+ /**
+ * See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
+ * itself does not have any way of knowing about required fields that
+ * aren't actually present in the set, it is up to the caller to check
+ * that all required fields are present.
+ */
+ @SuppressWarnings("unchecked")
+ public boolean isInitialized() {
+ for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ for (Message element : (List<Message>) entry.getValue()) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!((Message) entry.getValue()).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Like {@link #isInitialized()}, but also checks for the presence of
+ * all required fields in the given type.
+ */
+ @SuppressWarnings("unchecked")
+ public boolean isInitialized(Descriptor type) {
+ // Check that all required fields are present.
+ for (FieldDescriptor field : type.getFields()) {
+ if (field.isRequired()) {
+ if (!hasField(field)) {
+ return false;
+ }
+ }
+ }
+
+ // Check that embedded messages are initialized.
+ return isInitialized();
+ }
+
+ /** See {@link Message.Builder#mergeFrom(Message)}. */
+ @SuppressWarnings("unchecked")
+ public void mergeFrom(Message other) {
+ // Note: We don't attempt to verify that other's fields have valid
+ // types. Doing so would be a losing battle. We'd have to verify
+ // all sub-messages as well, and we'd have to make copies of all of
+ // them to insure that they don't change after verification (since
+ // the Message interface itself cannot enforce immutability of
+ // implementations).
+ // TODO(kenton): Provide a function somewhere called makeDeepCopy()
+ // which allows people to make secure deep copies of messages.
+
+ for (Map.Entry<FieldDescriptor, Object> entry :
+ other.getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ List existingValue = (List)fields.get(field);
+ if (existingValue == null) {
+ existingValue = new ArrayList();
+ fields.put(field, existingValue);
+ }
+ existingValue.addAll((List)entry.getValue());
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ Message existingValue = (Message)fields.get(field);
+ if (existingValue == null) {
+ setField(field, entry.getValue());
+ } else {
+ setField(field,
+ existingValue.newBuilderForType()
+ .mergeFrom(existingValue)
+ .mergeFrom((Message)entry.getValue())
+ .build());
+ }
+ } else {
+ setField(field, entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
+ */
+ @SuppressWarnings("unchecked")
+ public void mergeFrom(FieldSet other) {
+ for (Map.Entry<FieldDescriptor, Object> entry : other.fields.entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ Object value = entry.getValue();
+
+ if (field.isRepeated()) {
+ List existingValue = (List)fields.get(field);
+ if (existingValue == null) {
+ existingValue = new ArrayList();
+ fields.put(field, existingValue);
+ }
+ existingValue.addAll((List)value);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ Message existingValue = (Message)fields.get(field);
+ if (existingValue == null) {
+ setField(field, value);
+ } else {
+ setField(field,
+ existingValue.newBuilderForType()
+ .mergeFrom(existingValue)
+ .mergeFrom((Message)value)
+ .build());
+ }
+ } else {
+ setField(field, value);
+ }
+ }
+ }
+
+ // TODO(kenton): Move parsing code into AbstractMessage, since it no longer
+ // uses any special knowledge from FieldSet.
+
+ /**
+ * See {@link Message.Builder#mergeFrom(CodedInputStream)}.
+ * @param builder The {@code Builder} for the target message.
+ */
+ public static void mergeFrom(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
+ builder, tag)) {
+ // end group tag
+ break;
+ }
+ }
+ }
+
+ /**
+ * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
+ * ExtensionRegistry, Message.Builder)}, but parses a single field.
+ * @param tag The tag, which should have already been read.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean mergeFieldFrom(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder,
+ int tag) throws java.io.IOException {
+ Descriptor type = builder.getDescriptorForType();
+
+ if (type.getOptions().getMessageSetWireFormat() &&
+ tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+ mergeMessageSetExtensionFromCodedStream(
+ input, unknownFields, extensionRegistry, builder);
+ return true;
+ }
+
+ int wireType = WireFormat.getTagWireType(tag);
+ int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ FieldDescriptor field;
+ Message defaultInstance = null;
+
+ if (type.isExtensionNumber(fieldNumber)) {
+ ExtensionRegistry.ExtensionInfo extension =
+ extensionRegistry.findExtensionByNumber(type, fieldNumber);
+ if (extension == null) {
+ field = null;
+ } else {
+ field = extension.descriptor;
+ defaultInstance = extension.defaultInstance;
+ }
+ } else {
+ field = type.findFieldByNumber(fieldNumber);
+ }
+
+ if (field == null ||
+ wireType != WireFormat.getWireFormatForFieldType(field.getType())) {
+ // Unknown field or wrong wire type. Skip.
+ return unknownFields.mergeFieldFrom(tag, input);
+ } else {
+ Object value;
+ switch (field.getType()) {
+ case GROUP: {
+ Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
+ }
+ case MESSAGE: {
+ Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
+ }
+ case ENUM: {
+ int rawValue = input.readEnum();
+ value = field.getEnumType().findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ unknownFields.mergeVarintField(fieldNumber, rawValue);
+ return true;
+ }
+ break;
+ }
+ default:
+ value = input.readPrimitiveField(field.getType());
+ break;
+ }
+
+ if (field.isRepeated()) {
+ builder.addRepeatedField(field, value);
+ } else {
+ builder.setField(field, value);
+ }
+ }
+
+ return true;
+ }
+
+ /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
+ private static void mergeMessageSetExtensionFromCodedStream(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder) throws java.io.IOException {
+ Descriptor type = builder.getDescriptorForType();
+
+ // The wire format for MessageSet is:
+ // message MessageSet {
+ // repeated group Item = 1 {
+ // required int32 typeId = 2;
+ // required bytes message = 3;
+ // }
+ // }
+ // "typeId" is the extension's field number. The extension can only be
+ // a message type, where "message" contains the encoded bytes of that
+ // message.
+ //
+ // In practice, we will probably never see a MessageSet item in which
+ // the message appears before the type ID, or where either field does not
+ // appear exactly once. However, in theory such cases are valid, so we
+ // should be prepared to accept them.
+
+ int typeId = 0;
+ ByteString rawBytes = null; // If we encounter "message" before "typeId"
+ Message.Builder subBuilder = null;
+ FieldDescriptor field = null;
+
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+ typeId = input.readUInt32();
+ // Zero is not a valid type ID.
+ if (typeId != 0) {
+ ExtensionRegistry.ExtensionInfo extension =
+ extensionRegistry.findExtensionByNumber(type, typeId);
+ if (extension != null) {
+ field = extension.descriptor;
+ subBuilder = extension.defaultInstance.newBuilderForType();
+ Message originalMessage = (Message)builder.getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ if (rawBytes != null) {
+ // We already encountered the message. Parse it now.
+ subBuilder.mergeFrom(
+ CodedInputStream.newInstance(rawBytes.newInput()));
+ rawBytes = null;
+ }
+ } else {
+ // Unknown extension number. If we already saw data, put it
+ // in rawBytes.
+ if (rawBytes != null) {
+ unknownFields.mergeField(typeId,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(rawBytes)
+ .build());
+ rawBytes = null;
+ }
+ }
+ }
+ } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+ if (typeId == 0) {
+ // We haven't seen a type ID yet, so we have to store the raw bytes
+ // for now.
+ rawBytes = input.readBytes();
+ } else if (subBuilder == null) {
+ // We don't know how to parse this. Ignore it.
+ unknownFields.mergeField(typeId,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(input.readBytes())
+ .build());
+ } else {
+ // We already know the type, so we can parse directly from the input
+ // with no copying. Hooray!
+ input.readMessage(subBuilder, extensionRegistry);
+ }
+ } else {
+ // Unknown tag. Skip it.
+ if (!input.skipField(tag)) {
+ break; // end of group
+ }
+ }
+ }
+
+ input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+ if (subBuilder != null) {
+ builder.setField(field, subBuilder.build());
+ }
+ }
+
+ /** See {@link Message#writeTo(CodedOutputStream)}. */
+ public void writeTo(CodedOutputStream output)
+ throws java.io.IOException {
+ for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
+ writeField(entry.getKey(), entry.getValue(), output);
+ }
+ }
+
+ /** Write a single field. */
+ public void writeField(FieldDescriptor field, Object value,
+ CodedOutputStream output) throws java.io.IOException {
+ if (field.isExtension() &&
+ field.getContainingType().getOptions().getMessageSetWireFormat()) {
+ output.writeMessageSetExtension(field.getNumber(), (Message)value);
+ } else {
+ if (field.isRepeated()) {
+ for (Object element : (List)value) {
+ output.writeField(field.getType(), field.getNumber(), element);
+ }
+ } else {
+ output.writeField(field.getType(), field.getNumber(), value);
+ }
+ }
+ }
+
+ /**
+ * See {@link Message#getSerializedSize()}. It's up to the caller to cache
+ * the resulting size if desired.
+ */
+ public int getSerializedSize() {
+ int size = 0;
+ for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ Object value = entry.getValue();
+
+ if (field.isExtension() &&
+ field.getContainingType().getOptions().getMessageSetWireFormat()) {
+ size += CodedOutputStream.computeMessageSetExtensionSize(
+ field.getNumber(), (Message)value);
+ } else {
+ if (field.isRepeated()) {
+ for (Object element : (List)value) {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), element);
+ }
+ } else {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), value);
+ }
+ }
+ }
+ return size;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
new file mode 100644
index 00000000..957965b7
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -0,0 +1,1219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * All generated protocol message classes extend this class. This class
+ * implements most of the Message and Builder interfaces using Java reflection.
+ * Users can ignore this class and pretend that generated messages implement
+ * the Message interface directly.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessage extends AbstractMessage {
+ protected GeneratedMessage() {}
+
+ private UnknownFieldSet unknownFields = UnknownFieldSet.getDefaultInstance();
+
+ /**
+ * Get the FieldAccessorTable for this type. We can't have the message
+ * class pass this in to the constructor because of bootstrapping trouble
+ * with DescriptorProtos.
+ */
+ protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+ public Descriptor getDescriptorForType() {
+ return internalGetFieldAccessorTable().descriptor;
+ }
+
+ /** Internal helper which returns a mutable map. */
+ private final Map<FieldDescriptor, Object> getAllFieldsMutable() {
+ TreeMap<FieldDescriptor, Object> result =
+ new TreeMap<FieldDescriptor, Object>();
+ Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+ for (FieldDescriptor field : descriptor.getFields()) {
+ if (field.isRepeated()) {
+ List value = (List)getField(field);
+ if (!value.isEmpty()) {
+ result.put(field, value);
+ }
+ } else {
+ if (hasField(field)) {
+ result.put(field, getField(field));
+ }
+ }
+ }
+ return result;
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return Collections.unmodifiableMap(getAllFieldsMutable());
+ }
+
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).has(this);
+ }
+
+ public Object getField(FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).get(this);
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field)
+ .getRepeatedCount(this);
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ return internalGetFieldAccessorTable().getField(field)
+ .getRepeated(this, index);
+ }
+
+ public final UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ @SuppressWarnings("unchecked")
+ public abstract static class Builder <BuilderType extends Builder>
+ extends AbstractMessage.Builder<BuilderType> {
+ protected Builder() {}
+
+ /**
+ * Get the message being built. We don't just pass this to the
+ * constructor because it becomes null when build() is called.
+ */
+ protected abstract GeneratedMessage internalGetResult();
+
+ /**
+ * Get the FieldAccessorTable for this type. We can't have the message
+ * class pass this in to the constructor because of bootstrapping trouble
+ * with DescriptorProtos.
+ */
+ private FieldAccessorTable internalGetFieldAccessorTable() {
+ return internalGetResult().internalGetFieldAccessorTable();
+ }
+
+ public BuilderType mergeFrom(Message other) {
+ if (other.getDescriptorForType() !=
+ internalGetFieldAccessorTable().descriptor) {
+ throw new IllegalArgumentException("Message type mismatch.");
+ }
+
+ for (Map.Entry<FieldDescriptor, Object> entry :
+ other.getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ // Concatenate repeated fields.
+ for (Object element : (List) entry.getValue()) {
+ addRepeatedField(field, element);
+ }
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE &&
+ hasField(field)) {
+ // Merge singular embedded messages.
+ Message oldValue = (Message) getField(field);
+ setField(field,
+ oldValue.newBuilderForType()
+ .mergeFrom(oldValue)
+ .mergeFrom((Message) entry.getValue())
+ .buildPartial());
+ } else {
+ // Just overwrite.
+ setField(field, entry.getValue());
+ }
+ }
+ return (BuilderType)this;
+ }
+
+ public Descriptor getDescriptorForType() {
+ return internalGetFieldAccessorTable().descriptor;
+ }
+
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return internalGetResult().getAllFields();
+ }
+
+ public Message.Builder newBuilderForField(
+ Descriptors.FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).newBuilder();
+ }
+
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return internalGetResult().hasField(field);
+ }
+
+ public Object getField(Descriptors.FieldDescriptor field) {
+ if (field.isRepeated()) {
+ // The underlying list object is still modifiable at this point.
+ // Make sure not to expose the modifiable list to the caller.
+ return Collections.unmodifiableList(
+ (List)internalGetResult().getField(field));
+ } else {
+ return internalGetResult().getField(field);
+ }
+ }
+
+ public BuilderType setField(Descriptors.FieldDescriptor field,
+ Object value) {
+ internalGetFieldAccessorTable().getField(field).set(this, value);
+ return (BuilderType)this;
+ }
+
+ public BuilderType clearField(Descriptors.FieldDescriptor field) {
+ internalGetFieldAccessorTable().getField(field).clear(this);
+ return (BuilderType)this;
+ }
+
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ return internalGetResult().getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(Descriptors.FieldDescriptor field,
+ int index) {
+ return internalGetResult().getRepeatedField(field, index);
+ }
+
+ public BuilderType setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value) {
+ internalGetFieldAccessorTable().getField(field)
+ .setRepeated(this, index, value);
+ return (BuilderType)this;
+ }
+
+ public BuilderType addRepeatedField(Descriptors.FieldDescriptor field,
+ Object value) {
+ internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
+ return (BuilderType)this;
+ }
+
+ public final UnknownFieldSet getUnknownFields() {
+ return internalGetResult().unknownFields;
+ }
+
+ public final BuilderType setUnknownFields(UnknownFieldSet unknownFields) {
+ internalGetResult().unknownFields = unknownFields;
+ return (BuilderType)this;
+ }
+
+ public final BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) {
+ GeneratedMessage result = internalGetResult();
+ result.unknownFields =
+ UnknownFieldSet.newBuilder(result.unknownFields)
+ .mergeFrom(unknownFields)
+ .build();
+ return (BuilderType)this;
+ }
+
+ public boolean isInitialized() {
+ return internalGetResult().isInitialized();
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ int tag)
+ throws IOException {
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ protected <T> void addAll(Iterable<T> values, Collection<? super T> list) {
+ if (values instanceof Collection) {
+ @SuppressWarnings("unsafe")
+ Collection<T> collection = (Collection<T>) values;
+ list.addAll(collection);
+ } else {
+ for (T value : values) {
+ list.add(value);
+ }
+ }
+ }
+ }
+
+ // =================================================================
+ // Extensions-related stuff
+
+ /**
+ * Generated message classes for message types that contain extension ranges
+ * subclass this.
+ *
+ * <p>This class implements type-safe accessors for extensions. They
+ * implement all the same operations that you can do with normal fields --
+ * e.g. "has", "get", and "getCount" -- but for extensions. The extensions
+ * are identified using instances of the class {@link GeneratedExtension};
+ * the protocol compiler generates a static instance of this class for every
+ * extension in its input. Through the magic of generics, all is made
+ * type-safe.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then you might write code like:
+ *
+ * <pre>
+ * MyProto.Foo foo = getFoo();
+ * int i = foo.getExtension(MyProto.bar);
+ * </pre>
+ *
+ * <p>See also {@link ExtendableBuilder}.
+ */
+ public abstract static class ExtendableMessage<
+ MessageType extends ExtendableMessage>
+ extends GeneratedMessage {
+ protected ExtendableMessage() {}
+ private final FieldSet extensions = FieldSet.newFieldSet();
+
+ private final void verifyExtensionContainingType(
+ GeneratedExtension<MessageType, ?> extension) {
+ if (extension.getDescriptor().getContainingType() !=
+ getDescriptorForType()) {
+ // This can only happen if someone uses unchecked operations.
+ throw new IllegalArgumentException(
+ "Extension is for type \"" +
+ extension.getDescriptor().getContainingType().getFullName() +
+ "\" which does not match message type \"" +
+ getDescriptorForType().getFullName() + "\".");
+ }
+ }
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ GeneratedExtension<MessageType, ?> extension) {
+ verifyExtensionContainingType(extension);
+ return extensions.hasField(extension.getDescriptor());
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ GeneratedExtension<MessageType, List<Type>> extension) {
+ verifyExtensionContainingType(extension);
+ return extensions.getRepeatedFieldCount(extension.getDescriptor());
+ }
+
+ /** Get the value of an extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ GeneratedExtension<MessageType, Type> extension) {
+ verifyExtensionContainingType(extension);
+ Object value = extensions.getField(extension.getDescriptor());
+ if (value == null) {
+ return (Type)extension.getMessageDefaultInstance();
+ } else {
+ return (Type)extension.fromReflectionType(value);
+ }
+ }
+
+ /** Get one element of a repeated extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ GeneratedExtension<MessageType, List<Type>> extension, int index) {
+ verifyExtensionContainingType(extension);
+ return (Type)extension.singularFromReflectionType(
+ extensions.getRepeatedField(extension.getDescriptor(), index));
+ }
+
+ /** Called by subclasses to check if all extensions are initialized. */
+ protected boolean extensionsAreInitialized() {
+ return extensions.isInitialized();
+ }
+
+ /**
+ * Used by subclasses to serialize extensions. Extension ranges may be
+ * interleaved with field numbers, but we must write them in canonical
+ * (sorted by field number) order. ExtensionWriter helps us write
+ * individual ranges of extensions at once.
+ */
+ protected class ExtensionWriter {
+ // Imagine how much simpler this code would be if Java iterators had
+ // a way to get the next element without advancing the iterator.
+
+ final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
+ extensions.iterator();
+ Map.Entry<FieldDescriptor, Object> next = null;
+
+ private ExtensionWriter() {
+ if (iter.hasNext()) {
+ next = iter.next();
+ }
+ }
+
+ public void writeUntil(int end, CodedOutputStream output)
+ throws IOException {
+ while (next != null && next.getKey().getNumber() < end) {
+ extensions.writeField(next.getKey(), next.getValue(), output);
+ if (iter.hasNext()) {
+ next = iter.next();
+ } else {
+ next = null;
+ }
+ }
+ }
+ }
+
+ protected ExtensionWriter newExtensionWriter() {
+ return new ExtensionWriter();
+ }
+
+ /** Called by subclasses to compute the size of extensions. */
+ protected int extensionsSerializedSize() {
+ return extensions.getSerializedSize();
+ }
+
+ // ---------------------------------------------------------------
+ // Reflection
+
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+ result.putAll(extensions.getAllFields());
+ return Collections.unmodifiableMap(result);
+ }
+
+ public boolean hasField(FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.hasField(field);
+ } else {
+ return super.hasField(field);
+ }
+ }
+
+ public Object getField(FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ Object value = extensions.getField(field);
+ if (value == null) {
+ // Lacking an ExtensionRegistry, we have no way to determine the
+ // extension's real type, so we return a DynamicMessage.
+ return DynamicMessage.getDefaultInstance(field.getMessageType());
+ } else {
+ return value;
+ }
+ } else {
+ return super.getField(field);
+ }
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.getRepeatedFieldCount(field);
+ } else {
+ return super.getRepeatedFieldCount(field);
+ }
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.getRepeatedField(field, index);
+ } else {
+ return super.getRepeatedField(field, index);
+ }
+ }
+
+ private void verifyContainingType(FieldDescriptor field) {
+ if (field.getContainingType() != getDescriptorForType()) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+ }
+
+ /**
+ * Generated message builders for message types that contain extension ranges
+ * subclass this.
+ *
+ * <p>This class implements type-safe accessors for extensions. They
+ * implement all the same operations that you can do with normal fields --
+ * e.g. "get", "set", and "add" -- but for extensions. The extensions are
+ * identified using instances of the class {@link GeneratedExtension}; the
+ * protocol compiler generates a static instance of this class for every
+ * extension in its input. Through the magic of generics, all is made
+ * type-safe.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then you might write code like:
+ *
+ * <pre>
+ * MyProto.Foo foo =
+ * MyProto.Foo.newBuilder()
+ * .setExtension(MyProto.bar, 123)
+ * .build();
+ * </pre>
+ *
+ * <p>See also {@link ExtendableMessage}.
+ */
+ @SuppressWarnings("unchecked")
+ public abstract static class ExtendableBuilder<
+ MessageType extends ExtendableMessage,
+ BuilderType extends ExtendableBuilder>
+ extends GeneratedMessage.Builder<BuilderType> {
+ protected ExtendableBuilder() {}
+ protected abstract ExtendableMessage<MessageType> internalGetResult();
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ GeneratedExtension<MessageType, ?> extension) {
+ return internalGetResult().hasExtension(extension);
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ GeneratedExtension<MessageType, List<Type>> extension) {
+ return internalGetResult().getExtensionCount(extension);
+ }
+
+ /** Get the value of an extension. */
+ public final <Type> Type getExtension(
+ GeneratedExtension<MessageType, Type> extension) {
+ return internalGetResult().getExtension(extension);
+ }
+
+ /** Get one element of a repeated extension. */
+ public final <Type> Type getExtension(
+ GeneratedExtension<MessageType, List<Type>> extension, int index) {
+ return internalGetResult().getExtension(extension, index);
+ }
+
+ /** Set the value of an extension. */
+ public final <Type> BuilderType setExtension(
+ GeneratedExtension<MessageType, Type> extension, Type value) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.setField(extension.getDescriptor(),
+ extension.toReflectionType(value));
+ return (BuilderType)this;
+ }
+
+ /** Set the value of one element of a repeated extension. */
+ public final <Type> BuilderType setExtension(
+ GeneratedExtension<MessageType, List<Type>> extension,
+ int index, Type value) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.setRepeatedField(
+ extension.getDescriptor(), index,
+ extension.singularToReflectionType(value));
+ return (BuilderType)this;
+ }
+
+ /** Append a value to a repeated extension. */
+ public final <Type> BuilderType addExtension(
+ GeneratedExtension<MessageType, List<Type>> extension, Type value) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.addRepeatedField(
+ extension.getDescriptor(), extension.singularToReflectionType(value));
+ return (BuilderType)this;
+ }
+
+ /** Clear an extension. */
+ public final <Type> BuilderType clearExtension(
+ GeneratedExtension<MessageType, ?> extension) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.clearField(extension.getDescriptor());
+ return (BuilderType)this;
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field or an extension.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ int tag)
+ throws IOException {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ return message.extensions.mergeFieldFrom(
+ input, unknownFields, extensionRegistry, this, tag);
+ }
+
+ // ---------------------------------------------------------------
+ // Reflection
+
+ // We don't have to override the get*() methods here because they already
+ // just forward to the underlying message.
+
+ public BuilderType setField(FieldDescriptor field, Object value) {
+ if (field.isExtension()) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.setField(field, value);
+ return (BuilderType)this;
+ } else {
+ return super.setField(field, value);
+ }
+ }
+
+ public BuilderType clearField(Descriptors.FieldDescriptor field) {
+ if (field.isExtension()) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.clearField(field);
+ return (BuilderType)this;
+ } else {
+ return super.clearField(field);
+ }
+ }
+
+ public BuilderType setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value) {
+ if (field.isExtension()) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.setRepeatedField(field, index, value);
+ return (BuilderType)this;
+ } else {
+ return super.setRepeatedField(field, index, value);
+ }
+ }
+
+ public BuilderType addRepeatedField(Descriptors.FieldDescriptor field,
+ Object value) {
+ if (field.isExtension()) {
+ ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.addRepeatedField(field, value);
+ return (BuilderType)this;
+ } else {
+ return super.addRepeatedField(field, value);
+ }
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** For use by generated code only. */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, Type>
+ newGeneratedExtension(FieldDescriptor descriptor, Class<Type> type) {
+ if (descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "Must call newRepeatedGeneratedExtension() for repeated types.");
+ }
+ return new GeneratedExtension<ContainingType, Type>(descriptor, type);
+ }
+
+ /** For use by generated code only. */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, List<Type>>
+ newRepeatedGeneratedExtension(
+ FieldDescriptor descriptor, Class<Type> type) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "Must call newGeneratedExtension() for non-repeated types.");
+ }
+ return new GeneratedExtension<ContainingType, List<Type>>(descriptor, type);
+ }
+
+ /**
+ * Type used to represent generated extensions. The protocol compiler
+ * generates a static singleton instance of this class for each extension.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then, {@code MyProto.Foo.bar} has type
+ * {@code GeneratedExtension<MyProto.Foo, Integer>}.
+ *
+ * <p>In general, users should ignore the details of this type, and simply use
+ * these static singletons as parameters to the extension accessors defined
+ * in {@link ExtendableMessage} and {@link ExtendableBuilder}.
+ */
+ public static final class GeneratedExtension<
+ ContainingType extends Message, Type> {
+ // TODO(kenton): Find ways to avoid using Java reflection within this
+ // class. Also try to avoid suppressing unchecked warnings.
+
+ private GeneratedExtension(FieldDescriptor descriptor, Class type) {
+ if (!descriptor.isExtension()) {
+ throw new IllegalArgumentException(
+ "GeneratedExtension given a regular (non-extension) field.");
+ }
+
+ this.descriptor = descriptor;
+ this.type = type;
+
+ switch (descriptor.getJavaType()) {
+ case MESSAGE:
+ enumValueOf = null;
+ enumGetValueDescriptor = null;
+ messageDefaultInstance =
+ (Message)invokeOrDie(getMethodOrDie(type, "getDefaultInstance"),
+ null);
+ break;
+ case ENUM:
+ enumValueOf = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ enumGetValueDescriptor = getMethodOrDie(type, "getValueDescriptor");
+ messageDefaultInstance = null;
+ break;
+ default:
+ enumValueOf = null;
+ enumGetValueDescriptor = null;
+ messageDefaultInstance = null;
+ break;
+ }
+ }
+
+ private final FieldDescriptor descriptor;
+ private final Class type;
+ private final Method enumValueOf;
+ private final Method enumGetValueDescriptor;
+ private final Message messageDefaultInstance;
+
+ public FieldDescriptor getDescriptor() { return descriptor; }
+
+ /**
+ * If the extension is an embedded message or group, returns the default
+ * instance of the message.
+ */
+ @SuppressWarnings("unchecked")
+ public Message getMessageDefaultInstance() {
+ return messageDefaultInstance;
+ }
+
+ /**
+ * Convert from the type used by the reflection accessors to the type used
+ * by native accessors. E.g., for enums, the reflection accessors use
+ * EnumValueDescriptors but the native accessors use the generated enum
+ * type.
+ */
+ @SuppressWarnings("unchecked")
+ private Object fromReflectionType(Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
+ descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ // Must convert the whole list.
+ List result = new ArrayList();
+ for (Object element : (List)value) {
+ result.add(singularFromReflectionType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularFromReflectionType(value);
+ }
+ }
+
+ /**
+ * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
+ * type, this converts a single element.
+ */
+ private Object singularFromReflectionType(Object value) {
+ switch (descriptor.getJavaType()) {
+ case MESSAGE:
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // It seems the copy of the embedded message stored inside the
+ // extended message is not of the exact type the user was
+ // expecting. This can happen if a user defines a
+ // GeneratedExtension manually and gives it a different type.
+ // This should not happen in normal use. But, to be nice, we'll
+ // copy the message to whatever type the caller was expecting.
+ return messageDefaultInstance.newBuilderForType()
+ .mergeFrom((Message)value).build();
+ }
+ case ENUM:
+ return invokeOrDie(enumValueOf, null, (EnumValueDescriptor)value);
+ default:
+ return value;
+ }
+ }
+
+ /**
+ * Convert from the type used by the native accessors to the type used
+ * by reflection accessors. E.g., for enums, the reflection accessors use
+ * EnumValueDescriptors but the native accessors use the generated enum
+ * type.
+ */
+ @SuppressWarnings("unchecked")
+ private Object toReflectionType(Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ // Must convert the whole list.
+ List result = new ArrayList();
+ for (Object element : (List)value) {
+ result.add(singularToReflectionType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularToReflectionType(value);
+ }
+ }
+
+ /**
+ * Like {@link #toReflectionType(Object)}, but if the type is a repeated
+ * type, this converts a single element.
+ */
+ private Object singularToReflectionType(Object value) {
+ switch (descriptor.getJavaType()) {
+ case ENUM:
+ return invokeOrDie(enumGetValueDescriptor, value);
+ default:
+ return value;
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+ @SuppressWarnings("unchecked")
+ private static Method getMethodOrDie(
+ Class clazz, String name, Class... params) {
+ try {
+ return clazz.getMethod(name, params);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ "Generated message class \"" + clazz.getName() +
+ "\" missing method \"" + name + "\".", e);
+ }
+ }
+
+ /** Calls invoke and throws a RuntimeException if it fails. */
+ private static Object invokeOrDie(
+ Method method, Object object, Object... params) {
+ try {
+ return method.invoke(object, params);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Couldn't use Java reflection to implement protocol message " +
+ "reflection.", e);
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException)cause;
+ } else if (cause instanceof Error) {
+ throw (Error)cause;
+ } else {
+ throw new RuntimeException(
+ "Unexpected exception thrown by generated accessor method.", cause);
+ }
+ }
+ }
+
+ /**
+ * Users should ignore this class. This class provides the implementation
+ * with access to the fields of a message object using Java reflection.
+ */
+ public static final class FieldAccessorTable {
+ /**
+ * Construct a FieldAccessorTable for a particular message class. Only
+ * one FieldAccessorTable should ever be constructed per class.
+ *
+ * @param descriptor The type's descriptor.
+ * @param camelCaseNames The camelcase names of all fields in the message.
+ * These are used to derive the accessor method names.
+ * @param messageClass The message type.
+ * @param builderClass The builder type.
+ */
+ public FieldAccessorTable(
+ Descriptor descriptor,
+ String[] camelCaseNames,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ this.descriptor = descriptor;
+ fields = new FieldAccessor[descriptor.getFields().size()];
+
+ for (int i = 0; i < fields.length; i++) {
+ FieldDescriptor field = descriptor.getFields().get(i);
+ if (field.isRepeated()) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields[i] = new RepeatedMessageFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ fields[i] = new RepeatedEnumFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else {
+ fields[i] = new RepeatedFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ }
+ } else {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields[i] = new SingularMessageFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ fields[i] = new SingularEnumFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else {
+ fields[i] = new SingularFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ }
+ }
+ }
+ }
+
+ private final Descriptor descriptor;
+ private final FieldAccessor[] fields;
+
+ /** Get the FieldAccessor for a particular field. */
+ private FieldAccessor getField(FieldDescriptor field) {
+ if (field.getContainingType() != descriptor) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ } else if (field.isExtension()) {
+ // If this type had extensions, it would subclass ExtendableMessage,
+ // which overrides the reflection interface to handle extensions.
+ throw new IllegalArgumentException(
+ "This type does not have extensions.");
+ }
+ return fields[field.getIndex()];
+ }
+
+ /**
+ * Abstract interface that provides access to a single field. This is
+ * implemented differently depending on the field type and cardinality.
+ */
+ private static interface FieldAccessor {
+ Object get(GeneratedMessage message);
+ void set(GeneratedMessage.Builder builder, Object value);
+ Object getRepeated(GeneratedMessage message, int index);
+ void setRepeated(GeneratedMessage.Builder builder,
+ int index, Object value);
+ void addRepeated(GeneratedMessage.Builder builder, Object value);
+ boolean has(GeneratedMessage message);
+ int getRepeatedCount(GeneratedMessage message);
+ void clear(GeneratedMessage.Builder builder);
+ Message.Builder newBuilder();
+ }
+
+ // ---------------------------------------------------------------
+
+ private static class SingularFieldAccessor implements FieldAccessor {
+ SingularFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+ type = getMethod.getReturnType();
+ setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+ hasMethod =
+ getMethodOrDie(messageClass, "has" + camelCaseName);
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ }
+
+ // Note: We use Java reflection to call public methods rather than
+ // access private fields directly as this avoids runtime security
+ // checks.
+ Class type;
+ Method getMethod;
+ Method setMethod;
+ Method hasMethod;
+ Method clearMethod;
+
+ public Object get(GeneratedMessage message) {
+ return invokeOrDie(getMethod, message);
+ }
+ public void set(GeneratedMessage.Builder builder, Object value) {
+ invokeOrDie(setMethod, builder, value);
+ }
+ public Object getRepeated(GeneratedMessage message, int index) {
+ throw new UnsupportedOperationException(
+ "getRepeatedField() called on a singular field.");
+ }
+ public void setRepeated(GeneratedMessage.Builder builder,
+ int index, Object value) {
+ throw new UnsupportedOperationException(
+ "setRepeatedField() called on a singular field.");
+ }
+ public void addRepeated(GeneratedMessage.Builder builder, Object value) {
+ throw new UnsupportedOperationException(
+ "addRepeatedField() called on a singular field.");
+ }
+ public boolean has(GeneratedMessage message) {
+ return (Boolean)invokeOrDie(hasMethod, message);
+ }
+ public int getRepeatedCount(GeneratedMessage message) {
+ throw new UnsupportedOperationException(
+ "getRepeatedFieldSize() called on a singular field.");
+ }
+ public void clear(GeneratedMessage.Builder builder) {
+ invokeOrDie(clearMethod, builder);
+ }
+ public Message.Builder newBuilder() {
+ throw new UnsupportedOperationException(
+ "newBuilderForField() called on a non-Message type.");
+ }
+ }
+
+ private static class RepeatedFieldAccessor implements FieldAccessor {
+ RepeatedFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ getMethod = getMethodOrDie(messageClass, "get" + camelCaseName + "List");
+
+ getRepeatedMethod =
+ getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+ type = getRepeatedMethod.getReturnType();
+ setRepeatedMethod =
+ getMethodOrDie(builderClass, "set" + camelCaseName,
+ Integer.TYPE, type);
+ addRepeatedMethod =
+ getMethodOrDie(builderClass, "add" + camelCaseName, type);
+ getCountMethod =
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ }
+
+ Class type;
+ Method getMethod;
+ Method getRepeatedMethod;
+ Method setRepeatedMethod;
+ Method addRepeatedMethod;
+ Method getCountMethod;
+ Method clearMethod;
+
+ public Object get(GeneratedMessage message) {
+ return invokeOrDie(getMethod, message);
+ }
+ public void set(GeneratedMessage.Builder builder, Object value) {
+ // Add all the elements individually. This serves two purposes:
+ // 1) Verifies that each element has the correct type.
+ // 2) Insures that the caller cannot modify the list later on and
+ // have the modifications be reflected in the message.
+ clear(builder);
+ for (Object element : (List)value) {
+ addRepeated(builder, element);
+ }
+ }
+ public Object getRepeated(GeneratedMessage message, int index) {
+ return invokeOrDie(getRepeatedMethod, message, index);
+ }
+ public void setRepeated(GeneratedMessage.Builder builder,
+ int index, Object value) {
+ invokeOrDie(setRepeatedMethod, builder, index, value);
+ }
+ public void addRepeated(GeneratedMessage.Builder builder, Object value) {
+ invokeOrDie(addRepeatedMethod, builder, value);
+ }
+ public boolean has(GeneratedMessage message) {
+ throw new UnsupportedOperationException(
+ "hasField() called on a singular field.");
+ }
+ public int getRepeatedCount(GeneratedMessage message) {
+ return (Integer)invokeOrDie(getCountMethod, message);
+ }
+ public void clear(GeneratedMessage.Builder builder) {
+ invokeOrDie(clearMethod, builder);
+ }
+ public Message.Builder newBuilder() {
+ throw new UnsupportedOperationException(
+ "newBuilderForField() called on a non-Message type.");
+ }
+ }
+
+ // ---------------------------------------------------------------
+
+ private static final class SingularEnumFieldAccessor
+ extends SingularFieldAccessor {
+ SingularEnumFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ valueOfMethod = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ getValueDescriptorMethod =
+ getMethodOrDie(type, "getValueDescriptor");
+ }
+
+ private Method valueOfMethod;
+ private Method getValueDescriptorMethod;
+
+ public Object get(GeneratedMessage message) {
+ return invokeOrDie(getValueDescriptorMethod, super.get(message));
+ }
+ public void set(GeneratedMessage.Builder builder, Object value) {
+ super.set(builder, invokeOrDie(valueOfMethod, null, value));
+ }
+ }
+
+ private static final class RepeatedEnumFieldAccessor
+ extends RepeatedFieldAccessor {
+ RepeatedEnumFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ valueOfMethod = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ getValueDescriptorMethod =
+ getMethodOrDie(type, "getValueDescriptor");
+ }
+
+ private Method valueOfMethod;
+ private Method getValueDescriptorMethod;
+
+ @SuppressWarnings("unchecked")
+ public Object get(GeneratedMessage message) {
+ List newList = new ArrayList();
+ for (Object element : (List)super.get(message)) {
+ newList.add(invokeOrDie(getValueDescriptorMethod, element));
+ }
+ return Collections.unmodifiableList(newList);
+ }
+ public Object getRepeated(GeneratedMessage message, int index) {
+ return invokeOrDie(getValueDescriptorMethod,
+ super.getRepeated(message, index));
+ }
+ public void setRepeated(GeneratedMessage.Builder builder,
+ int index, Object value) {
+ super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null, value));
+ }
+ public void addRepeated(GeneratedMessage.Builder builder, Object value) {
+ super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
+ }
+ }
+
+ // ---------------------------------------------------------------
+
+ private static final class SingularMessageFieldAccessor
+ extends SingularFieldAccessor {
+ SingularMessageFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
+ }
+
+ private Method newBuilderMethod;
+
+ private Object coerceType(Object value) {
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // The value is not the exact right message type. However, if it
+ // is an alternative implementation of the same type -- e.g. a
+ // DynamicMessage -- we should accept it. In this case we can make
+ // a copy of the message.
+ return ((Message.Builder)invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message)value).build();
+ }
+ }
+
+ public void set(GeneratedMessage.Builder builder, Object value) {
+ super.set(builder, coerceType(value));
+ }
+ public Message.Builder newBuilder() {
+ return (Message.Builder)invokeOrDie(newBuilderMethod, null);
+ }
+ }
+
+ private static final class RepeatedMessageFieldAccessor
+ extends RepeatedFieldAccessor {
+ RepeatedMessageFieldAccessor(
+ FieldDescriptor descriptor, String camelCaseName,
+ Class<? extends GeneratedMessage> messageClass,
+ Class<? extends GeneratedMessage.Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
+ }
+
+ private Method newBuilderMethod;
+
+ private Object coerceType(Object value) {
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // The value is not the exact right message type. However, if it
+ // is an alternative implementation of the same type -- e.g. a
+ // DynamicMessage -- we should accept it. In this case we can make
+ // a copy of the message.
+ return ((Message.Builder)invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message)value).build();
+ }
+ }
+
+ public void setRepeated(GeneratedMessage.Builder builder,
+ int index, Object value) {
+ super.setRepeated(builder, index, coerceType(value));
+ }
+ public void addRepeated(GeneratedMessage.Builder builder, Object value) {
+ super.addRepeated(builder, coerceType(value));
+ }
+ public Message.Builder newBuilder() {
+ return (Message.Builder)invokeOrDie(newBuilderMethod, null);
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
new file mode 100644
index 00000000..d57da4ed
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way,
+ * e.g. it contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferException extends IOException {
+ public InvalidProtocolBufferException(String description) {
+ super(description);
+ }
+
+ static InvalidProtocolBufferException truncatedMessage() {
+ return new InvalidProtocolBufferException(
+ "While parsing a protocol message, the input ended unexpectedly " +
+ "in the middle of a field. This could mean either than the " +
+ "input has been truncated or that an embedded message " +
+ "misreported its own length.");
+ }
+
+ static InvalidProtocolBufferException negativeSize() {
+ return new InvalidProtocolBufferException(
+ "CodedInputStream encountered an embedded string or message " +
+ "which claimed to have negative size.");
+ }
+
+ static InvalidProtocolBufferException malformedVarint() {
+ return new InvalidProtocolBufferException(
+ "CodedInputStream encountered a malformed varint.");
+ }
+
+ static InvalidProtocolBufferException invalidTag() {
+ return new InvalidProtocolBufferException(
+ "Protocol message contained an invalid tag (zero).");
+ }
+
+ static InvalidProtocolBufferException invalidEndTag() {
+ return new InvalidProtocolBufferException(
+ "Protocol message end-group tag did not match expected tag.");
+ }
+
+ static InvalidProtocolBufferException invalidWireType() {
+ return new InvalidProtocolBufferException(
+ "Protocol message tag had invalid wire type.");
+ }
+
+ static InvalidProtocolBufferException recursionLimitExceeded() {
+ return new InvalidProtocolBufferException(
+ "Protocol message had too many levels of nesting. May be malicious. " +
+ "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+ }
+
+ static InvalidProtocolBufferException sizeLimitExceeded() {
+ return new InvalidProtocolBufferException(
+ "Protocol message was too large. May be malicious. " +
+ "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java
new file mode 100644
index 00000000..f45f7df9
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Message.java
@@ -0,0 +1,415 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
+// mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface Message {
+ /**
+ * Get the message's type's descriptor. This differs from the
+ * {@code getDescriptor()} method of generated message classes in that
+ * this method is an abstract method of the {@code Message} interface
+ * whereas {@code getDescriptor()} is a static method of a specific class.
+ * They return the same thing.
+ */
+ Descriptors.Descriptor getDescriptorForType();
+
+ /**
+ * Get an instance of the type with all fields set to their default values.
+ * This may or may not be a singleton. This differs from the
+ * {@code getDefaultInstance()} method of generated message classes in that
+ * this method is an abstract method of the {@code Message} interface
+ * whereas {@code getDefaultInstance()} is a static method of a specific
+ * class. They return the same thing.
+ */
+ Message getDefaultInstanceForType();
+
+ /**
+ * Returns a collection of all the fields in this message which are set
+ * and their corresponding values. A singular ("required" or "optional")
+ * field is set iff hasField() returns true for that field. A "repeated"
+ * field is set iff getRepeatedFieldSize() is greater than zero. The
+ * values are exactly what would be returned by calling
+ * {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
+ * is guaranteed to be a sorted map, so iterating over it will return fields
+ * in order by field number.
+ */
+ Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+ /**
+ * Returns true if the given field is set. This is exactly equivalent to
+ * calling the generated "has" accessor method corresponding to the field.
+ * @throws IllegalArgumentException The field is a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Obtains the value of the given field, or the default value if it is
+ * not set. For primitive fields, the boxed primitive value is returned.
+ * For enum fields, the EnumValueDescriptor for the value is returend. For
+ * embedded message fields, the sub-message is returned. For repeated
+ * fields, a java.util.List is returned.
+ */
+ Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets the number of elements of a repeated field. This is exactly
+ * equivalent to calling the generated "Count" accessor method corresponding
+ * to the field.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets an element of a repeated field. For primitive fields, the boxed
+ * primitive value is returned. For enum fields, the EnumValueDescriptor
+ * for the value is returend. For embedded message fields, the sub-message
+ * is returned.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+ /** Get the {@link UnknownFieldSet} for this message. */
+ UnknownFieldSet getUnknownFields();
+
+ /**
+ * Returns true if all required fields in the message and all embedded
+ * messages are set, false otherwise.
+ */
+ boolean isInitialized();
+
+ /**
+ * Serializes the message and writes it to {@code output}. This does not
+ * flush or close the stream.
+ */
+ void writeTo(CodedOutputStream output) throws IOException;
+
+ /**
+ * Get the number of bytes required to encode this message. The result
+ * is only computed on the first call and memoized after that.
+ */
+ int getSerializedSize();
+
+ // -----------------------------------------------------------------
+ // Comparison and hashing
+
+ /**
+ * Compares the specified object with this message for equality. Returns
+ * <tt>true</tt> if the given object is a message of the same type (as
+ * defined by {@code getDescriptorForType()}) and has identical values for
+ * all of its fields.
+ *
+ * @param other object to be compared for equality with this message
+ * @return <tt>true</tt> if the specified object is equal to this message
+ */
+ boolean equals(Object other);
+
+ /**
+ * Returns the hash code value for this message. The hash code of a message
+ * is defined to be <tt>getDescriptor().hashCode() ^ map.hashCode()</tt>,
+ * where <tt>map</tt> is a map of field numbers to field values.
+ *
+ * @return the hash code value for this message
+ * @see Map#hashCode()
+ */
+ int hashCode();
+
+ // -----------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Converts the message to a string in protocol buffer text format. This is
+ * just a trivial wrapper around {@link TextFormat#printToString(Message)}.
+ */
+ String toString();
+
+ /**
+ * Serializes the message to a {@code ByteString} and returns it. This is
+ * just a trivial wrapper around
+ * {@link #writeTo(CodedOutputStream)}.
+ */
+ ByteString toByteString();
+
+ /**
+ * Serializes the message to a {@code byte} array and returns it. This is
+ * just a trivial wrapper around
+ * {@link #writeTo(CodedOutputStream)}.
+ */
+ byte[] toByteArray();
+
+ /**
+ * Serializes the message and writes it to {@code output}. This is just a
+ * trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
+ * not flush or close the stream.
+ */
+ void writeTo(OutputStream output) throws IOException;
+
+ // =================================================================
+ // Builders
+
+ /**
+ * Constructs a new builder for a message of the same type as this message.
+ */
+ Builder newBuilderForType();
+
+ /**
+ * Abstract interface implemented by Protocol Message builders.
+ */
+ public static interface Builder extends Cloneable {
+ /** Resets all fields to their default values. */
+ Builder clear();
+
+ /**
+ * Merge {@code other} into the message being built. {@code other} must
+ * have the exact same type as {@code this} (i.e.
+ * {@code getDescriptorForType() == other.getDescriptorForType()}).
+ *
+ * Merging occurs as follows. For each field:<br>
+ * * For singular primitive fields, if the field is set in {@code other},
+ * then {@code other}'s value overwrites the value in this message.<br>
+ * * For singular message fields, if the field is set in {@code other},
+ * it is merged into the corresponding sub-message of this message
+ * using the same merging rules.<br>
+ * * For repeated fields, the elements in {@code other} are concatenated
+ * with the elements in this message.
+ *
+ * This is equivalent to the {@code Message::MergeFrom} method in C++.
+ */
+ Builder mergeFrom(Message other);
+
+ /**
+ * Construct the final message. Once this is called, the Builder is no
+ * longer valid, and calling any other method may throw a
+ * NullPointerException. If you need to continue working with the builder
+ * after calling {@code build()}, {@code clone()} it first.
+ * @throws UninitializedMessageException The message is missing one or more
+ * required fields (i.e. {@link #isInitialized()} returns false).
+ * Use {@link #buildPartial()} to bypass this check.
+ */
+ Message build();
+
+ /**
+ * Like {@link #build()}, but does not throw an exception if the message
+ * is missing required fields. Instead, a partial message is returned.
+ */
+ Message buildPartial();
+
+ /**
+ * Clones the Builder.
+ * @see Object#clone()
+ */
+ Builder clone();
+
+ /**
+ * Returns true if all required fields in the message and all embedded
+ * messages are set, false otherwise.
+ */
+ boolean isInitialized();
+
+ /**
+ * Parses a message of this type from the input and merges it with this
+ * message, as if using {@link Builder#mergeFrom(Message)}.
+ *
+ * <p>Warning: This does not verify that all required fields are present in
+ * the input message. If you call {@link #build()} without setting all
+ * required fields, it will throw an {@link UninitializedMessageException},
+ * which is a {@code RuntimeException} and thus might not be caught. There
+ * are a few good ways to deal with this:
+ * <ul>
+ * <li>Call {@link #isInitialized()} to verify that all required fields
+ * are set before building.
+ * <li>Parse the message separately using one of the static
+ * {@code parseFrom} methods, then use {@link #mergeFrom(Message)}
+ * to merge it with this one. {@code parseFrom} will throw an
+ * {@link InvalidProtocolBufferException} (an {@code IOException})
+ * if some required fields are missing.
+ * <li>Use {@code buildPartial()} to build, which ignores missing
+ * required fields.
+ * </ul>
+ *
+ * <p>Note: The caller should call
+ * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
+ * verify that the last tag seen was the appropriate end-group tag,
+ * or zero for EOF.
+ */
+ Builder mergeFrom(CodedInputStream input) throws IOException;
+
+ /**
+ * Like {@link Builder#mergeFrom(CodedInputStream)}, but also
+ * parses extensions. The extensions that you want to be able to parse
+ * must be registered in {@code extensionRegistry}. Extensions not in
+ * the registry will be treated as unknown fields.
+ */
+ Builder mergeFrom(CodedInputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException;
+
+ /**
+ * Get the message's type's descriptor.
+ * See {@link Message#getDescriptorForType()}.
+ */
+ Descriptors.Descriptor getDescriptorForType();
+
+ /**
+ * Get the message's type's default instance.
+ * See {@link Message#getDefaultInstanceForType()}.
+ */
+ Message getDefaultInstanceForType();
+
+ /**
+ * Like {@link Message#getAllFields()}. The returned map may or may not
+ * reflect future changes to the builder. Either way, the returned map is
+ * itself unmodifiable.
+ */
+ Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+ /**
+ * Create a Builder for messages of the appropriate type for the given
+ * field. Messages built with this can then be passed to setField(),
+ * setRepeatedField(), or addRepeatedField().
+ */
+ Builder newBuilderForField(Descriptors.FieldDescriptor field);
+
+ /** Like {@link Message#hasField(Descriptors.FieldDescriptor)} */
+ boolean hasField(Descriptors.FieldDescriptor field);
+
+ /** Like {@link Message#getField(Descriptors.FieldDescriptor)} */
+ Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Sets a field to the given value. The value must be of the correct type
+ * for this field, i.e. the same type that
+ * {@link Message#getField(Descriptors.FieldDescriptor)} would return.
+ */
+ Builder setField(Descriptors.FieldDescriptor field, Object value);
+
+ /**
+ * Clears the field. This is exactly equivalent to calling the generated
+ * "clear" accessor method corresponding to the field.
+ */
+ Builder clearField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Like {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}
+ */
+ int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /**
+ * Like {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}
+ */
+ Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+ /**
+ * Sets an element of a repeated field to the given value. The value must
+ * be of the correct type for this field, i.e. the same type that
+ * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
+ * return.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Builder setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value);
+
+ /**
+ * Like {@code setRepeatedField}, but appends the value as a new element.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
+
+ /** Get the {@link UnknownFieldSet} for this message. */
+ UnknownFieldSet getUnknownFields();
+
+ /** Set the {@link UnknownFieldSet} for this message. */
+ Builder setUnknownFields(UnknownFieldSet unknownFields);
+
+ /**
+ * Merge some unknown fields into the {@link UnknownFieldSet} for this
+ * message.
+ */
+ Builder mergeUnknownFields(UnknownFieldSet unknownFields);
+
+ // ---------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(ByteString data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(byte[] data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse a message of this type from {@code input} and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}. Note that this method always
+ * reads the <i>entire</i> input (unless it throws an exception). If you
+ * want it to stop earlier, you will need to wrap your input in some
+ * wrapper stream that limits reading. Despite usually reading the entire
+ * input, this does not close the stream.
+ */
+ Builder mergeFrom(InputStream input) throws IOException;
+
+ /**
+ * Parse a message of this type from {@code input} and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(InputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcCallback.java b/java/src/main/java/com/google/protobuf/RpcCallback.java
new file mode 100644
index 00000000..a99077fa
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcCallback.java
@@ -0,0 +1,27 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Interface for an RPC callback, normally called when an RPC completes.
+ * {@code ParameterType} is normally the method's response message type.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcCallback<ParameterType> {
+ void run(ParameterType parameter);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcChannel.java b/java/src/main/java/com/google/protobuf/RpcChannel.java
new file mode 100644
index 00000000..1c7dcfc0
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcChannel.java
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
+ * communication line to a {@link Service} which can be used to call that
+ * {@link Service}'s methods. The {@link Service} may be running on another
+ * machine. Normally, you should not call an {@code RpcChannel} directly, but
+ * instead construct a stub {@link Service} wrapping it. Example:
+ *
+ * <pre>
+ * RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
+ * RpcController controller = rpcImpl.newController();
+ * MyService service = MyService.newStub(channel);
+ * service.myMethod(controller, request, callback);
+ * </pre>
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcChannel {
+ /**
+ * Call the given method of the remote service. This method is similar to
+ * {@code Service.callMethod()} with one important difference: the caller
+ * decides the types of the {@code Message} objects, not the callee. The
+ * request may be of any type as long as
+ * {@code request.getDescriptor() == method.getInputType()}.
+ * The response passed to the callback will be of the same type as
+ * {@code responsePrototype} (which must have
+ * {@code getDescriptor() == method.getOutputType()}).
+ */
+ void callMethod(Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request,
+ Message responsePrototype,
+ RpcCallback<Message> done);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcController.java b/java/src/main/java/com/google/protobuf/RpcController.java
new file mode 100644
index 00000000..7495bb8a
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcController.java
@@ -0,0 +1,98 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * <p>An {@code 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.
+ *
+ * <p>The methods provided by the {@code 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).
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcController {
+ // -----------------------------------------------------------------
+ // These calls may be made from the client side only. Their results
+ // are undefined on the server side (may throw RuntimeExceptions).
+
+ /**
+ * Resets the RpcController to its initial state so that it may be reused in
+ * a new call. This can be called from the client side only. It must not
+ * be called while an RPC is in progress.
+ */
+ void reset();
+
+ /**
+ * After a call has finished, returns true if the call failed. The possible
+ * reasons for failure depend on the RPC implementation. {@code failed()}
+ * most only be called on the client side, and must not be called before a
+ * call has finished.
+ */
+ boolean failed();
+
+ /**
+ * If {@code failed()} is {@code true}, returns a human-readable description
+ * of the error.
+ */
+ String errorText();
+
+ /**
+ * 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.
+ */
+ void startCancel();
+
+ // -----------------------------------------------------------------
+ // These calls may be made from the server side only. Their results
+ // are undefined on the client side (may throw RuntimeExceptions).
+
+ /**
+ * Causes {@code failed()} to return true on the client side. {@code reason}
+ * will be incorporated into the message returned by {@code 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 {@code setFailed()}.
+ */
+ void setFailed(String reason);
+
+ /**
+ * If {@code true}, indicates that the client canceled the RPC, so the server
+ * may as well give up on replying to it. This method must be called on the
+ * server side only. The server should still call the final "done" callback.
+ */
+ boolean isCanceled();
+
+ /**
+ * Asks that the given callback be called when the RPC is canceled. The
+ * parameter passed to the callback will always be {@code null}. 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.
+ *
+ * <p>{@code notifyOnCancel()} must be called no more than once per request.
+ * It must be called on the server side only.
+ */
+ void notifyOnCancel(RpcCallback<Object> callback);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/src/main/java/com/google/protobuf/RpcUtil.java
new file mode 100644
index 00000000..13cd4aca
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcUtil.java
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Grab-bag of utility functions useful when dealing with RPCs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class RpcUtil {
+ private RpcUtil() {}
+
+ /**
+ * Take an {@code RcpCallabck<Message>} and convert it to an
+ * {@code RpcCallback} accepting a specific message type. This is always
+ * type-safe (parameter type contravariance).
+ */
+ @SuppressWarnings("unchecked")
+ public static <Type extends Message> RpcCallback<Type>
+ specializeCallback(final RpcCallback<Message> originalCallback) {
+ return (RpcCallback<Type>)originalCallback;
+ // The above cast works, but only due to technical details of the Java
+ // implementation. A more theoretically correct -- but less efficient --
+ // implementation would be as follows:
+ // return new RpcCallback<Type>() {
+ // public void run(Type parameter) {
+ // originalCallback.run(parameter);
+ // }
+ // };
+ }
+
+ /**
+ * Take an {@code RcpCallabck} accepting a specific message type and convert
+ * it to an {@code RcpCallabck<Message>}. The generalized callback will
+ * accept any message object which has the same descriptor, and will convert
+ * it to the correct class before calling the original callback. However,
+ * if the generalized callback is given a message with a different descriptor,
+ * an exception will be thrown.
+ */
+ public static <Type extends Message>
+ RpcCallback<Message> generalizeCallback(
+ final RpcCallback<Type> originalCallback,
+ final Class<Type> originalClass,
+ final Type defaultInstance) {
+ return new RpcCallback<Message>() {
+ public void run(Message parameter) {
+ Type typedParameter;
+ try {
+ typedParameter = originalClass.cast(parameter);
+ } catch (ClassCastException e) {
+ typedParameter = copyAsType(defaultInstance, parameter);
+ }
+ originalCallback.run(typedParameter);
+ }
+ };
+ }
+
+ /**
+ * Creates a new message of type "Type" which is a copy of "source". "source"
+ * must have the same descriptor but may be a different class (e.g.
+ * DynamicMessage).
+ */
+ @SuppressWarnings("unchecked")
+ private static <Type extends Message> Type copyAsType(
+ Type typeDefaultInstance, Message source) {
+ return (Type)typeDefaultInstance.newBuilderForType()
+ .mergeFrom(source)
+ .build();
+ }
+
+ /**
+ * Creates a callback which can only be called once. This may be useful for
+ * security, when passing a callback to untrusted code: most callbacks do
+ * not expect to be called more than once, so doing so may expose bugs if it
+ * is not prevented.
+ */
+ public static <ParameterType>
+ RpcCallback<ParameterType> newOneTimeCallback(
+ final RpcCallback<ParameterType> originalCallback) {
+ return new RpcCallback<ParameterType>() {
+ boolean alreadyCalled = false;
+ public void run(ParameterType parameter) {
+ synchronized(this) {
+ if (alreadyCalled) {
+ throw new AlreadyCalledException();
+ }
+ alreadyCalled = true;
+ }
+
+ originalCallback.run(parameter);
+ }
+ };
+ }
+
+ /**
+ * Exception thrown when a one-time callback is called more than once.
+ */
+ public static final class AlreadyCalledException extends RuntimeException {
+ public AlreadyCalledException() {
+ super("This RpcCallback was already called and cannot be called " +
+ "multiple times.");
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Service.java b/java/src/main/java/com/google/protobuf/Service.java
new file mode 100644
index 00000000..53b2557e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Service.java
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * 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).
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface Service {
+ /**
+ * Get the {@code ServiceDescriptor} describing this service and its methods.
+ */
+ Descriptors.ServiceDescriptor getDescriptorForType();
+
+ /**
+ * <p>Call a method of the service specified by MethodDescriptor. This is
+ * normally implemented as a simple {@code switch()} that calls the standard
+ * definitions of the service's methods.
+ *
+ * <p>Preconditions:
+ * <ul>
+ * <li>{@code method.getService() == getDescriptorForType()}
+ * <li>{@code request} is of the exact same class as the object returned by
+ * {@code getRequestPrototype(method)}.
+ * <li>{@code 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
+ * {@code RpcController} the server-side RPC implementation uses.
+ * </ul>
+ *
+ * <p>Postconditions:
+ * <ul>
+ * <li>{@code done} will be called when the method is complete. This may be
+ * before {@code callMethod()} returns or it may be at some point in
+ * the future.
+ * <li>The parameter to {@code done} is the response. It must be of the
+ * exact same type as would be returned by
+ * {@code getResponsePrototype(method)}.
+ * <li>If the RPC failed, the parameter to {@code done} will be
+ * {@code null}. Further details about the failure can be found by
+ * querying {@code controller}.
+ * </ul>
+ */
+ void callMethod(Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request,
+ RpcCallback<Message> done);
+
+ /**
+ * <p>{@code callMethod()} requires that the request passed in is of a
+ * particular subclass of {@code Message}. {@code getRequestPrototype()}
+ * gets the default instances of this type for a given method. You can then
+ * call {@code Message.newBuilderForType()} on this instance to
+ * construct a builder to build an object which you can then pass to
+ * {@code callMethod()}.
+ *
+ * <p>Example:
+ * <pre>
+ * MethodDescriptor method =
+ * service.getDescriptorForType().findMethodByName("Foo");
+ * Message request =
+ * stub.getRequestPrototype(method).newBuilderForType()
+ * .mergeFrom(input).build();
+ * service.callMethod(method, request, callback);
+ * </pre>
+ */
+ Message getRequestPrototype(Descriptors.MethodDescriptor method);
+
+ /**
+ * Like {@code getRequestPrototype()}, but gets a prototype of the response
+ * message. {@code getResponsePrototype()} is generally not needed because
+ * the {@code Service} implementation constructs the response message itself,
+ * but it may be useful in some cases to know ahead of time what type of
+ * object will be returned.
+ */
+ Message getResponsePrototype(Descriptors.MethodDescriptor method);
+}
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
new file mode 100644
index 00000000..c4fdfe64
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -0,0 +1,1242 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provide ascii text parsing and formatting support for proto2 instances.
+ * The implementation largely follows google/protobuf/text_format.cc.
+ *
+ * @author wenboz@google.com Wenbo Zhu
+ * @author kenton@google.com Kenton Varda
+ */
+public final class TextFormat {
+
+ /**
+ * Outputs a textual representation of the Protocol Message supplied into
+ * the parameter output. (This representation is the new version of the
+ * classic "ProtocolPrinter" output from the original Protocol Buffer system)
+ */
+ public static void print(Message message, Appendable output)
+ throws IOException {
+ TextGenerator generator = new TextGenerator(output);
+ print(message, generator);
+ }
+
+ /** Outputs a textual representation of {@code fields} to {@code output}. */
+ public static void print(UnknownFieldSet fields, Appendable output)
+ throws IOException {
+ TextGenerator generator = new TextGenerator(output);
+ printUnknownFields(fields, generator);
+ }
+
+ /**
+ * Like {@code print()}, but writes directly to a {@code String} and
+ * returns it.
+ */
+ public static String printToString(Message message) {
+ try {
+ StringBuilder text = new StringBuilder();
+ print(message, text);
+ return text.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Writing to a StringBuilder threw an IOException (should never " +
+ "happen).", e);
+ }
+ }
+
+ /**
+ * Like {@code print()}, but writes directly to a {@code String} and
+ * returns it.
+ */
+ public static String printToString(UnknownFieldSet fields) {
+ try {
+ StringBuilder text = new StringBuilder();
+ print(fields, text);
+ return text.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Writing to a StringBuilder threw an IOException (should never " +
+ "happen).", e);
+ }
+ }
+
+ private static void print(Message message, TextGenerator generator)
+ throws IOException {
+ Descriptor descriptor = message.getDescriptorForType();
+ for (Map.Entry<FieldDescriptor, Object> field :
+ message.getAllFields().entrySet()) {
+ printField(field.getKey(), field.getValue(), generator);
+ }
+ printUnknownFields(message.getUnknownFields(), generator);
+ }
+
+ public static void printField(FieldDescriptor field,
+ Object value,
+ TextGenerator generator)
+ throws IOException {
+ if (field.isRepeated()) {
+ // Repeated field. Print each element.
+ for (Object element : (List) value) {
+ printSingleField(field, element, generator);
+ }
+ } else {
+ printSingleField(field, value, generator);
+ }
+ }
+
+ private static void printSingleField(FieldDescriptor field,
+ Object value,
+ TextGenerator generator)
+ throws IOException {
+ if (field.isExtension()) {
+ generator.print("[");
+ // We special-case MessageSet elements for compatibility with proto1.
+ if (field.getContainingType().getOptions().getMessageSetWireFormat()
+ && (field.getType() == FieldDescriptor.Type.MESSAGE)
+ && (field.isOptional())
+ // object equality
+ && (field.getExtensionScope() == field.getMessageType())) {
+ generator.print(field.getMessageType().getFullName());
+ } else {
+ generator.print(field.getFullName());
+ }
+ generator.print("]");
+ } else {
+ if (field.getType() == FieldDescriptor.Type.GROUP) {
+ // Groups must be serialized with their original capitalization.
+ generator.print(field.getMessageType().getName());
+ } else {
+ generator.print(field.getName());
+ }
+ }
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ generator.print(" {\n");
+ generator.indent();
+ } else {
+ generator.print(": ");
+ }
+
+ printFieldValue(field, value, generator);
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ generator.outdent();
+ generator.print("}");
+ }
+ generator.print("\n");
+ }
+
+ private static void printFieldValue(FieldDescriptor field,
+ Object value,
+ TextGenerator generator)
+ throws IOException {
+ switch (field.getType()) {
+ case INT32:
+ case INT64:
+ case SINT32:
+ case SINT64:
+ case SFIXED32:
+ case SFIXED64:
+ case FLOAT:
+ case DOUBLE:
+ case BOOL:
+ // Good old toString() does what we want for these types.
+ generator.print(value.toString());
+ break;
+
+ case UINT32:
+ case FIXED32:
+ generator.print(unsignedToString((Integer) value));
+ break;
+
+ case UINT64:
+ case FIXED64:
+ generator.print(unsignedToString((Long) value));
+ break;
+
+ case STRING:
+ generator.print("\"");
+ generator.print(escapeText((String) value));
+ generator.print("\"");
+ break;
+
+ case BYTES: {
+ generator.print("\"");
+ generator.print(escapeBytes((ByteString) value));
+ generator.print("\"");
+ break;
+ }
+
+ case ENUM: {
+ generator.print(((EnumValueDescriptor) value).getName());
+ break;
+ }
+
+ case MESSAGE:
+ case GROUP:
+ print((Message) value, generator);
+ break;
+ }
+ }
+
+ private static void printUnknownFields(UnknownFieldSet unknownFields,
+ TextGenerator generator)
+ throws IOException {
+ for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+ unknownFields.asMap().entrySet()) {
+ String prefix = entry.getKey().toString() + ": ";
+ UnknownFieldSet.Field field = entry.getValue();
+
+ for (long value : field.getVarintList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(unsignedToString(value));
+ generator.print("\n");
+ }
+ for (int value : field.getFixed32List()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(String.format((Locale) null, "0x%08x", value));
+ generator.print("\n");
+ }
+ for (long value : field.getFixed64List()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(String.format((Locale) null, "0x%016x", value));
+ generator.print("\n");
+ }
+ for (ByteString value : field.getLengthDelimitedList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": \"");
+ generator.print(escapeBytes(value));
+ generator.print("\"\n");
+ }
+ for (UnknownFieldSet value : field.getGroupList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(" {\n");
+ generator.indent();
+ printUnknownFields(value, generator);
+ generator.outdent();
+ generator.print("}\n");
+ }
+ }
+ }
+
+ /** Convert an unsigned 32-bit integer to a string. */
+ private static String unsignedToString(int value) {
+ if (value >= 0) {
+ return Integer.toString(value);
+ } else {
+ return Long.toString(((long) value) & 0x00000000FFFFFFFFL);
+ }
+ }
+
+ /** Convert an unsigned 64-bit integer to a string. */
+ private static String unsignedToString(long value) {
+ if (value >= 0) {
+ return Long.toString(value);
+ } else {
+ // Pull off the most-significant bit so that BigInteger doesn't think
+ // the number is negative, then set it again using setBit().
+ return BigInteger.valueOf(value & 0x7FFFFFFFFFFFFFFFL)
+ .setBit(63).toString();
+ }
+ }
+
+ /**
+ * An inner class for writing text to the output stream.
+ */
+ static private final class TextGenerator {
+
+ Appendable output;
+ boolean atStartOfLine = true;
+ StringBuilder indent = new StringBuilder();
+
+ public TextGenerator(Appendable output) {
+ this.output = output;
+ }
+
+ /**
+ * Indent text by two spaces. After calling Indent(), two spaces will be
+ * inserted at the beginning of each line of text. Indent() may be called
+ * multiple times to produce deeper indents.
+ */
+ public void indent() {
+ indent.append(" ");
+ }
+
+ /**
+ * Reduces the current indent level by two spaces, or crashes if the indent
+ * level is zero.
+ */
+ public void outdent() {
+ int length = indent.length();
+ if (length == 0) {
+ throw new IllegalArgumentException(
+ " Outdent() without matching Indent().");
+ }
+ indent.delete(length - 2, length);
+ }
+
+ /**
+ * Print text to the output stream.
+ */
+ public void print(CharSequence text) throws IOException {
+ int size = text.length();
+ int pos = 0;
+
+ for (int i = 0; i < size; i++) {
+ if (text.charAt(i) == '\n') {
+ write(text.subSequence(pos, size), i - pos + 1);
+ pos = i + 1;
+ atStartOfLine = true;
+ }
+ }
+ write(text.subSequence(pos, size), size - pos);
+ }
+
+ private void write(CharSequence data, int size) throws IOException {
+ if (size == 0) {
+ return;
+ }
+ if (atStartOfLine) {
+ atStartOfLine = false;
+ output.append(indent);
+ }
+ output.append(data);
+ }
+ }
+
+ // =================================================================
+ // Parsing
+
+ /**
+ * Represents a stream of tokens parsed from a {@code String}.
+ *
+ * <p>The Java standard library provides many classes that you might think
+ * would be useful for implementing this, but aren't. For example:
+ *
+ * <ul>
+ * <li>{@code java.io.StreamTokenizer}: This almost does what we want -- or,
+ * at least, something that would get us close to what we want -- except
+ * for one fatal flaw: It automatically un-escapes strings using Java
+ * escape sequences, which do not include all the escape sequences we
+ * need to support (e.g. '\x').
+ * <li>{@code java.util.Scanner}: This seems like a great way at least to
+ * parse regular expressions out of a stream (so we wouldn't have to load
+ * the entire input into a single string before parsing). Sadly,
+ * {@code Scanner} requires that tokens be delimited with some delimiter.
+ * Thus, although the text "foo:" should parse to two tokens ("foo" and
+ * ":"), {@code Scanner} would recognize it only as a single token.
+ * Furthermore, {@code Scanner} provides no way to inspect the contents
+ * of delimiters, making it impossible to keep track of line and column
+ * numbers.
+ * </ul>
+ *
+ * <p>Luckily, Java's regular expression support does manage to be useful to
+ * us. (Barely: We need {@code Matcher.usePattern()}, which is new in
+ * Java 1.5.) So, we can use that, at least. Unfortunately, this implies
+ * that we need to have the entire input in one contiguous string.
+ */
+ private static final class Tokenizer {
+ private final CharSequence text;
+ private final Matcher matcher;
+ private String currentToken;
+
+ // The character index within this.text at which the current token begins.
+ private int pos = 0;
+
+ // The line and column numbers of the current token.
+ private int line = 0;
+ private int column = 0;
+
+ // The line and column numbers of the previous token (allows throwing
+ // errors *after* consuming).
+ private int previousLine = 0;
+ private int previousColumn = 0;
+
+ private static Pattern WHITESPACE = Pattern.compile("(\\s|(#[^\n]*$))*");
+ private static Pattern TOKEN = Pattern.compile(
+ "[a-zA-Z_][0-9a-zA-Z_+-]*|" + // an identifier
+ "[0-9+-][0-9a-zA-Z_.+-]*|" + // a number
+ "\"([^\"\n\\\\]|\\\\[^\n])*(\"|\\\\?$)|" + // a double-quoted string
+ "\'([^\"\n\\\\]|\\\\[^\n])*(\'|\\\\?$)"); // a single-quoted string
+
+ /** Construct a tokenizer that parses tokens from the given text. */
+ public Tokenizer(CharSequence text) {
+ this.text = text;
+ this.matcher = WHITESPACE.matcher(text);
+ skipWhitespace();
+ nextToken();
+ }
+
+ /** Are we at the end of the input? */
+ public boolean atEnd() {
+ return currentToken.length() == 0;
+ }
+
+ /** Advance to the next token. */
+ public void nextToken() {
+ previousLine = line;
+ previousColumn = column;
+
+ // Advance the line counter to the current position.
+ while (pos < matcher.regionStart()) {
+ if (text.charAt(pos) == '\n') {
+ ++line;
+ column = 0;
+ } else {
+ ++column;
+ }
+ ++pos;
+ }
+
+ // Match the next token.
+ if (matcher.regionStart() == matcher.regionEnd()) {
+ // EOF
+ currentToken = "";
+ } else {
+ matcher.usePattern(TOKEN);
+ if (matcher.lookingAt()) {
+ currentToken = matcher.group();
+ matcher.region(matcher.end(), matcher.regionEnd());
+ } else {
+ // Take one character.
+ currentToken = String.valueOf(text.charAt(pos));
+ matcher.region(pos + 1, matcher.regionEnd());
+ }
+
+ skipWhitespace();
+ }
+ }
+
+ /**
+ * Skip over any whitespace so that the matcher region starts at the next
+ * token.
+ */
+ private void skipWhitespace() {
+ matcher.usePattern(WHITESPACE);
+ if (matcher.lookingAt()) {
+ matcher.region(matcher.end(), matcher.regionEnd());
+ }
+ }
+
+ /**
+ * If the next token exactly matches {@code token}, consume it and return
+ * {@code true}. Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsume(String token) {
+ if (currentToken.equals(token)) {
+ nextToken();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * If the next token exactly matches {@code token}, consume it. Otherwise,
+ * throw a {@link ParseException}.
+ */
+ public void consume(String token) throws ParseException {
+ if (!tryConsume(token)) {
+ throw parseException("Expected \"" + token + "\".");
+ }
+ }
+
+ /**
+ * Returns {@code true} if the next token is an integer, but does
+ * not consume it.
+ */
+ public boolean lookingAtInteger() {
+ if (currentToken.length() == 0) {
+ return false;
+ }
+
+ char c = currentToken.charAt(0);
+ return ('0' <= c && c <= '9') ||
+ c == '-' || c == '+';
+ }
+
+ /**
+ * If the next token is an identifier, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public String consumeIdentifier() throws ParseException {
+ for (int i = 0; i < currentToken.length(); i++) {
+ char c = currentToken.charAt(i);
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9') ||
+ (c == '_') || (c == '.')) {
+ // OK
+ } else {
+ throw parseException("Expected identifier.");
+ }
+ }
+
+ String result = currentToken;
+ nextToken();
+ return result;
+ }
+
+ /**
+ * If the next token is a 32-bit signed integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public int consumeInt32() throws ParseException {
+ try {
+ int result = parseInt32(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 32-bit unsigned integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public int consumeUInt32() throws ParseException {
+ try {
+ int result = parseUInt32(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 64-bit signed integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public long consumeInt64() throws ParseException {
+ try {
+ long result = parseInt64(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 64-bit unsigned integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public long consumeUInt64() throws ParseException {
+ try {
+ long result = parseUInt64(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a double, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public double consumeDouble() throws ParseException {
+ try {
+ double result = Double.parseDouble(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw floatParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a float, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public float consumeFloat() throws ParseException {
+ try {
+ float result = Float.parseFloat(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw floatParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a boolean, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public boolean consumeBoolean() throws ParseException {
+ if (currentToken.equals("true")) {
+ nextToken();
+ return true;
+ } else if (currentToken.equals("false")) {
+ nextToken();
+ return false;
+ } else {
+ throw parseException("Expected \"true\" or \"false\".");
+ }
+ }
+
+ /**
+ * If the next token is a string, consume it and return its (unescaped)
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public String consumeString() throws ParseException {
+ return consumeByteString().toStringUtf8();
+ }
+
+ /**
+ * If the next token is a string, consume it, unescape it as a
+ * {@link ByteString}, and return it. Otherwise, throw a
+ * {@link ParseException}.
+ */
+ public ByteString consumeByteString() throws ParseException {
+ char quote = currentToken.length() > 0 ? currentToken.charAt(0) : '\0';
+ if (quote != '\"' && quote != '\'') {
+ throw parseException("Expected string.");
+ }
+
+ if (currentToken.length() < 2 ||
+ currentToken.charAt(currentToken.length() - 1) != quote) {
+ throw parseException("String missing ending quote.");
+ }
+
+ try {
+ String escaped = currentToken.substring(1, currentToken.length() - 1);
+ ByteString result = unescapeBytes(escaped);
+ nextToken();
+ return result;
+ } catch (InvalidEscapeSequence e) {
+ throw parseException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a {@link ParseException} with the current line and column
+ * numbers in the description, suitable for throwing.
+ */
+ public ParseException parseException(String description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new ParseException(
+ (line + 1) + ":" + (column + 1) + ": " + description);
+ }
+
+ /**
+ * Returns a {@link ParseException} with the line and column numbers of
+ * the previous token in the description, suitable for throwing.
+ */
+ public ParseException parseExceptionPreviousToken(String description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new ParseException(
+ (previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
+ }
+
+ /**
+ * Constructs an appropriate {@link ParseException} for the given
+ * {@code NumberFormatException} when trying to parse an integer.
+ */
+ private ParseException integerParseException(NumberFormatException e) {
+ return parseException("Couldn't parse integer: " + e.getMessage());
+ }
+
+ /**
+ * Constructs an appropriate {@link ParseException} for the given
+ * {@code NumberFormatException} when trying to parse a float or double.
+ */
+ private ParseException floatParseException(NumberFormatException e) {
+ return parseException("Couldn't parse number: " + e.getMessage());
+ }
+ }
+
+ /** Thrown when parsing an invalid text format message. */
+ public static class ParseException extends IOException {
+ public ParseException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public static void merge(Readable input,
+ Message.Builder builder)
+ throws ParseException, IOException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public static void merge(CharSequence input,
+ Message.Builder builder)
+ throws ParseException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public static void merge(Readable input,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder)
+ throws ParseException, IOException {
+ // Read the entire input to a String then parse that.
+
+ // If StreamTokenizer were not quite so crippled, or if there were a kind
+ // of Reader that could read in chunks that match some particular regex,
+ // or if we wanted to write a custom Reader to tokenize our stream, then
+ // we would not have to read to one big String. Alas, none of these is
+ // the case. Oh well.
+
+ merge(toStringBuilder(input), extensionRegistry, builder);
+ }
+
+ private static final int BUFFER_SIZE = 4096;
+
+ // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
+ // overhead is worthwhile
+ private static StringBuilder toStringBuilder(Readable input)
+ throws IOException {
+ StringBuilder text = new StringBuilder();
+ CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
+ while (true) {
+ int n = input.read(buffer);
+ if (n == -1) {
+ break;
+ }
+ buffer.flip();
+ text.append(buffer, 0, n);
+ }
+ return text;
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public static void merge(CharSequence input,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder)
+ throws ParseException {
+ Tokenizer tokenizer = new Tokenizer(input);
+
+ while (!tokenizer.atEnd()) {
+ mergeField(tokenizer, extensionRegistry, builder);
+ }
+ }
+
+ /**
+ * Parse a single field from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private static void mergeField(Tokenizer tokenizer,
+ ExtensionRegistry extensionRegistry,
+ Message.Builder builder)
+ throws ParseException {
+ FieldDescriptor field;
+ Descriptor type = builder.getDescriptorForType();
+ ExtensionRegistry.ExtensionInfo extension = null;
+
+ if (tokenizer.tryConsume("[")) {
+ // An extension.
+ StringBuilder name = new StringBuilder(tokenizer.consumeIdentifier());
+ while (tokenizer.tryConsume(".")) {
+ name.append(".");
+ name.append(tokenizer.consumeIdentifier());
+ }
+
+ extension = extensionRegistry.findExtensionByName(name.toString());
+
+ if (extension == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+ } else if (extension.descriptor.getContainingType() != type) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" does not extend message type \"" +
+ type.getFullName() + "\".");
+ }
+
+ tokenizer.consume("]");
+
+ field = extension.descriptor;
+ } else {
+ String name = tokenizer.consumeIdentifier();
+ field = type.findFieldByName(name);
+
+ // Group names are expected to be capitalized as they appear in the
+ // .proto file, which actually matches their type names, not their field
+ // names.
+ if (field == null) {
+ // Explicitly specify US locale so that this code does not break when
+ // executing in Turkey.
+ String lowerName = name.toLowerCase(Locale.US);
+ field = type.findFieldByName(lowerName);
+ // If the case-insensitive match worked but the field is NOT a group,
+ if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
+ field = null;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
+ !field.getMessageType().getName().equals(name)) {
+ field = null;
+ }
+
+ if (field == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Message type \"" + type.getFullName() +
+ "\" has no field named \"" + name + "\".");
+ }
+ }
+
+ Object value = null;
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ tokenizer.tryConsume(":"); // optional
+
+ String endToken;
+ if (tokenizer.tryConsume("<")) {
+ endToken = ">";
+ } else {
+ tokenizer.consume("{");
+ endToken = "}";
+ }
+
+ Message.Builder subBuilder;
+ if (extension == null) {
+ subBuilder = builder.newBuilderForField(field);
+ } else {
+ subBuilder = extension.defaultInstance.newBuilderForType();
+ }
+
+ while (!tokenizer.tryConsume(endToken)) {
+ if (tokenizer.atEnd()) {
+ throw tokenizer.parseException(
+ "Expected \"" + endToken + "\".");
+ }
+ mergeField(tokenizer, extensionRegistry, subBuilder);
+ }
+
+ value = subBuilder.build();
+
+ } else {
+ tokenizer.consume(":");
+
+ switch (field.getType()) {
+ case INT32:
+ case SINT32:
+ case SFIXED32:
+ value = tokenizer.consumeInt32();
+ break;
+
+ case INT64:
+ case SINT64:
+ case SFIXED64:
+ value = tokenizer.consumeInt64();
+ break;
+
+ case UINT32:
+ case FIXED32:
+ value = tokenizer.consumeUInt32();
+ break;
+
+ case UINT64:
+ case FIXED64:
+ value = tokenizer.consumeUInt64();
+ break;
+
+ case FLOAT:
+ value = tokenizer.consumeFloat();
+ break;
+
+ case DOUBLE:
+ value = tokenizer.consumeDouble();
+ break;
+
+ case BOOL:
+ value = tokenizer.consumeBoolean();
+ break;
+
+ case STRING:
+ value = tokenizer.consumeString();
+ break;
+
+ case BYTES:
+ value = tokenizer.consumeByteString();
+ break;
+
+ case ENUM: {
+ EnumDescriptor enumType = field.getEnumType();
+
+ if (tokenizer.lookingAtInteger()) {
+ int number = tokenizer.consumeInt32();
+ value = enumType.findValueByNumber(number);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName() +
+ "\" has no value with number " + number + ".");
+ }
+ } else {
+ String id = tokenizer.consumeIdentifier();
+ value = enumType.findValueByName(id);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName() +
+ "\" has no value named \"" + id + "\".");
+ }
+ }
+
+ break;
+ }
+
+ case MESSAGE:
+ case GROUP:
+ throw new RuntimeException("Can't get here.");
+ }
+ }
+
+ if (field.isRepeated()) {
+ builder.addRepeatedField(field, value);
+ } else {
+ builder.setField(field, value);
+ }
+ }
+
+ // =================================================================
+ // Utility functions
+ //
+ // Some of these methods are package-private because Descriptors.java uses
+ // them.
+
+ /**
+ * Escapes bytes in the format used in protocol buffer text format, which
+ * is the same as the format used for C string literals. All bytes
+ * that are not printable 7-bit ASCII characters are escaped, as well as
+ * backslash, single-quote, and double-quote characters. Characters for
+ * which no defined short-hand escape sequence is defined will be escaped
+ * using 3-digit octal sequences.
+ */
+ static String escapeBytes(ByteString input) {
+ StringBuilder builder = new StringBuilder(input.size());
+ for (int i = 0; i < input.size(); i++) {
+ byte b = input.byteAt(i);
+ switch (b) {
+ // Java does not recognize \a or \v, apparently.
+ case 0x07: builder.append("\\a" ); break;
+ case '\b': builder.append("\\b" ); break;
+ case '\f': builder.append("\\f" ); break;
+ case '\n': builder.append("\\n" ); break;
+ case '\r': builder.append("\\r" ); break;
+ case '\t': builder.append("\\t" ); break;
+ case 0x0b: builder.append("\\v" ); break;
+ case '\\': builder.append("\\\\"); break;
+ case '\'': builder.append("\\\'"); break;
+ case '"' : builder.append("\\\""); break;
+ default:
+ if (b >= 0x20) {
+ builder.append((char) b);
+ } else {
+ builder.append('\\');
+ builder.append((char) ('0' + ((b >>> 6) & 3)));
+ builder.append((char) ('0' + ((b >>> 3) & 7)));
+ builder.append((char) ('0' + (b & 7)));
+ }
+ break;
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Un-escape a byte sequence as escaped using
+ * {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with
+ * "\x") are also recognized.
+ */
+ static ByteString unescapeBytes(CharSequence input)
+ throws InvalidEscapeSequence {
+ byte[] result = new byte[input.length()];
+ int pos = 0;
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ if (c == '\\') {
+ if (i + 1 < input.length()) {
+ ++i;
+ c = input.charAt(i);
+ if (isOctal(c)) {
+ // Octal escape.
+ int code = digitValue(c);
+ if (i + 1 < input.length() && isOctal(input.charAt(i + 1))) {
+ ++i;
+ code = code * 8 + digitValue(input.charAt(i));
+ }
+ if (i + 1 < input.length() && isOctal(input.charAt(i + 1))) {
+ ++i;
+ code = code * 8 + digitValue(input.charAt(i));
+ }
+ result[pos++] = (byte)code;
+ } else {
+ switch (c) {
+ case 'a' : result[pos++] = 0x07; break;
+ case 'b' : result[pos++] = '\b'; break;
+ case 'f' : result[pos++] = '\f'; break;
+ case 'n' : result[pos++] = '\n'; break;
+ case 'r' : result[pos++] = '\r'; break;
+ case 't' : result[pos++] = '\t'; break;
+ case 'v' : result[pos++] = 0x0b; break;
+ case '\\': result[pos++] = '\\'; break;
+ case '\'': result[pos++] = '\''; break;
+ case '"' : result[pos++] = '\"'; break;
+
+ case 'x':
+ // hex escape
+ int code = 0;
+ if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
+ ++i;
+ code = digitValue(input.charAt(i));
+ } else {
+ throw new InvalidEscapeSequence(
+ "Invalid escape sequence: '\\x' with no digits");
+ }
+ if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
+ ++i;
+ code = code * 16 + digitValue(input.charAt(i));
+ }
+ result[pos++] = (byte)code;
+ break;
+
+ default:
+ throw new InvalidEscapeSequence(
+ "Invalid escape sequence: '\\" + c + "'");
+ }
+ }
+ } else {
+ throw new InvalidEscapeSequence(
+ "Invalid escape sequence: '\\' at end of string.");
+ }
+ } else {
+ result[pos++] = (byte)c;
+ }
+ }
+
+ return ByteString.copyFrom(result, 0, pos);
+ }
+
+ /**
+ * Thrown by {@link TextFormat#unescapeBytes} and
+ * {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
+ */
+ static class InvalidEscapeSequence extends IOException {
+ public InvalidEscapeSequence(String description) {
+ super(description);
+ }
+ }
+
+ /**
+ * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+ * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+ * individually as a 3-digit octal escape. Yes, it's weird.
+ */
+ static String escapeText(String input) {
+ return escapeBytes(ByteString.copyFromUtf8(input));
+ }
+
+ /**
+ * Un-escape a text string as escaped using {@link #escapeText(String)}.
+ * Two-digit hex escapes (starting with "\x") are also recognized.
+ */
+ static String unescapeText(String input) throws InvalidEscapeSequence {
+ return unescapeBytes(input).toStringUtf8();
+ }
+
+ /** Is this an octal digit? */
+ private static boolean isOctal(char c) {
+ return '0' <= c && c <= '7';
+ }
+
+ /** Is this a hex digit? */
+ private static boolean isHex(char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F');
+ }
+
+ /**
+ * Interpret a character as a digit (in any base up to 36) and return the
+ * numeric value. This is like {@code Character.digit()} but we don't accept
+ * non-ASCII digits.
+ */
+ private static int digitValue(char c) {
+ if ('0' <= c && c <= '9') {
+ return c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return c - 'A' + 10;
+ }
+ }
+
+ /**
+ * Parse a 32-bit signed integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively.
+ */
+ static int parseInt32(String text) throws NumberFormatException {
+ return (int) parseInteger(text, true, false);
+ }
+
+ /**
+ * Parse a 32-bit unsigned integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * result is coerced to a (signed) {@code int} when returned since Java has
+ * no unsigned integer type.
+ */
+ static int parseUInt32(String text) throws NumberFormatException {
+ return (int) parseInteger(text, false, false);
+ }
+
+ /**
+ * Parse a 64-bit signed integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively.
+ */
+ static long parseInt64(String text) throws NumberFormatException {
+ return parseInteger(text, true, true);
+ }
+
+ /**
+ * Parse a 64-bit unsigned integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * result is coerced to a (signed) {@code long} when returned since Java has
+ * no unsigned long type.
+ */
+ static long parseUInt64(String text) throws NumberFormatException {
+ return parseInteger(text, false, true);
+ }
+
+ private static long parseInteger(String text,
+ boolean isSigned,
+ boolean isLong)
+ throws NumberFormatException {
+ int pos = 0;
+
+ boolean negative = false;
+ if (text.startsWith("-", pos)) {
+ if (!isSigned) {
+ throw new NumberFormatException("Number must be positive: " + text);
+ }
+ ++pos;
+ negative = true;
+ }
+
+ int radix = 10;
+ if (text.startsWith("0x", pos)) {
+ pos += 2;
+ radix = 16;
+ } else if (text.startsWith("0", pos)) {
+ radix = 8;
+ }
+
+ String numberText = text.substring(pos);
+
+ long result = 0;
+ if (numberText.length() < 16) {
+ // Can safely assume no overflow.
+ result = Long.parseLong(numberText, radix);
+ if (negative) {
+ result = -result;
+ }
+
+ // Check bounds.
+ // No need to check for 64-bit numbers since they'd have to be 16 chars
+ // or longer to overflow.
+ if (!isLong) {
+ if (isSigned) {
+ if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit signed integer: " + text);
+ }
+ } else {
+ if (result >= (1L << 32) || result < 0) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit unsigned integer: " + text);
+ }
+ }
+ }
+ } else {
+ BigInteger bigValue = new BigInteger(numberText, radix);
+ if (negative) {
+ bigValue = bigValue.negate();
+ }
+
+ // Check bounds.
+ if (!isLong) {
+ if (isSigned) {
+ if (bigValue.bitLength() > 31) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit signed integer: " + text);
+ }
+ } else {
+ if (bigValue.bitLength() > 32) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit unsigned integer: " + text);
+ }
+ }
+ } else {
+ if (isSigned) {
+ if (bigValue.bitLength() > 63) {
+ throw new NumberFormatException(
+ "Number out of range for 64-bit signed integer: " + text);
+ }
+ } else {
+ if (bigValue.bitLength() > 64) {
+ throw new NumberFormatException(
+ "Number out of range for 64-bit unsigned integer: " + text);
+ }
+ }
+ }
+
+ result = bigValue.longValue();
+ }
+
+ return result;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
new file mode 100644
index 00000000..61c3e248
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
@@ -0,0 +1,146 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Thrown when attempting to build a protocol message that is missing required
+ * fields. This is a {@code RuntimeException} because it normally represents
+ * a programming error: it happens when some code which constructs a message
+ * fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
+ * throw this; they throw an {@link InvalidProtocolBufferException} if
+ * required fields are missing, because it is not a programming error to
+ * receive an incomplete message. In other words,
+ * {@code UninitializedMessageException} should never be thrown by correct
+ * code, but {@code InvalidProtocolBufferException} might be.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class UninitializedMessageException extends RuntimeException {
+ public UninitializedMessageException(Message message) {
+ this(findMissingFields(message));
+ }
+
+ private UninitializedMessageException(List<String> missingFields) {
+ super(buildDescription(missingFields));
+ this.missingFields = missingFields;
+ }
+
+ private final List<String> missingFields;
+
+ /**
+ * Get a list of human-readable names of required fields missing from this
+ * message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
+ */
+ public List<String> getMissingFields() {
+ return Collections.unmodifiableList(missingFields);
+ }
+
+ /**
+ * Converts this exception to an {@link InvalidProtocolBufferException}.
+ * When a parsed message is missing required fields, this should be thrown
+ * instead of {@code UninitializedMessageException}.
+ */
+ public InvalidProtocolBufferException asInvalidProtocolBufferException() {
+ return new InvalidProtocolBufferException(getMessage());
+ }
+
+ /** Construct the description string for this exception. */
+ private static String buildDescription(List<String> missingFields) {
+ StringBuilder description =
+ new StringBuilder("Message missing required fields: ");
+ boolean first = true;
+ for (String field : missingFields) {
+ if (first) {
+ first = false;
+ } else {
+ description.append(", ");
+ }
+ description.append(field);
+ }
+ return description.toString();
+ }
+
+ /**
+ * Populates {@code this.missingFields} with the full "path" of each
+ * missing required field in the given message.
+ */
+ private static List<String> findMissingFields(Message message) {
+ List<String> results = new ArrayList<String>();
+ findMissingFields(message, "", results);
+ return results;
+ }
+
+ /** Recursive helper implementing {@link #findMissingFields(Message)}. */
+ private static void findMissingFields(Message message, String prefix,
+ List<String> results) {
+ for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
+ if (field.isRequired() && !message.hasField(field)) {
+ results.add(prefix + field.getName());
+ }
+ }
+
+ for (Map.Entry<FieldDescriptor, Object> entry :
+ message.getAllFields().entrySet()) {
+ FieldDescriptor field = entry.getKey();
+ Object value = entry.getValue();
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ int i = 0;
+ for (Object element : (List) value) {
+ findMissingFields((Message) element,
+ subMessagePrefix(prefix, field, i++),
+ results);
+ }
+ } else {
+ if (message.hasField(field)) {
+ findMissingFields((Message) value,
+ subMessagePrefix(prefix, field, -1),
+ results);
+ }
+ }
+ }
+ }
+ }
+
+ private static String subMessagePrefix(String prefix,
+ FieldDescriptor field,
+ int index) {
+ StringBuilder result = new StringBuilder(prefix);
+ if (field.isExtension()) {
+ result.append('(')
+ .append(field.getFullName())
+ .append(')');
+ } else {
+ result.append(field.getName());
+ }
+ if (index != -1) {
+ result.append('[')
+ .append(index)
+ .append(']');
+ }
+ result.append('.');
+ return result.toString();
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
new file mode 100644
index 00000000..6bcc4309
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -0,0 +1,746 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.TreeMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@code UnknownFieldSet} is used to keep track of fields which were seen when
+ * parsing a protocol message but whose field numbers or types are unrecognized.
+ * This most frequently occurs when new fields are added to a message type
+ * and then messages containing those feilds are read by old software that was
+ * compiled before the new types were added.
+ *
+ * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
+ * {@link Message.Builder} contains an {@link UnknownFieldSet.Builder}).
+ *
+ * <p>Most users will never need to use this class.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class UnknownFieldSet {
+ private UnknownFieldSet() {}
+
+ /** Create a new {@link UnknownFieldSet.Builder}. */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Create a new {@link UnknownFieldSet.Builder} and initialize it to be a copy
+ * of {@code copyFrom}.
+ */
+ public static Builder newBuilder(UnknownFieldSet copyFrom) {
+ return new Builder().mergeFrom(copyFrom);
+ }
+
+ /** Get an empty {@code UnknownFieldSet}. */
+ public static UnknownFieldSet getDefaultInstance() {
+ return defaultInstance;
+ }
+ private static UnknownFieldSet defaultInstance =
+ new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
+
+ /**
+ * Construct an {@code UnknownFieldSet} around the given map. The map is
+ * expected to be immutable.
+ */
+ private UnknownFieldSet(Map<Integer, Field> fields) {
+ this.fields = fields;
+ }
+ private Map<Integer, Field> fields;
+
+ /** Get a map of fields in the set by number. */
+ public Map<Integer, Field> asMap() {
+ return fields;
+ }
+
+ /** Check if the given field number is present in the set. */
+ public boolean hasField(int number) {
+ return fields.containsKey(number);
+ }
+
+ /**
+ * Get a field by number. Returns an empty field if not present. Never
+ * returns {@code null}.
+ */
+ public Field getField(int number) {
+ Field result = fields.get(number);
+ return (result == null) ? Field.getDefaultInstance() : result;
+ }
+
+ /** Serializes the set and writes it to {@code output}. */
+ public void writeTo(CodedOutputStream output) throws IOException {
+ for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ entry.getValue().writeTo(entry.getKey(), output);
+ }
+ }
+
+ /**
+ * Converts the set to a string in protocol buffer text format. This is
+ * just a trivial wrapper around
+ * {@link TextFormat#printToString(UnknownFieldSet)}.
+ */
+ public final String toString() {
+ return TextFormat.printToString(this);
+ }
+
+ /**
+ * Serializes the message to a {@code ByteString} and returns it. This is
+ * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public final ByteString toByteString() {
+ try {
+ ByteString.CodedBuilder out =
+ ByteString.newCodedBuilder(getSerializedSize());
+ writeTo(out.getCodedOutput());
+ return out.build();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Serializes the message to a {@code byte} array and returns it. This is
+ * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public final byte[] toByteArray() {
+ try {
+ byte[] result = new byte[getSerializedSize()];
+ CodedOutputStream output = CodedOutputStream.newInstance(result);
+ writeTo(output);
+ output.checkNoSpaceLeft();
+ return result;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a byte array threw an IOException " +
+ "(should never happen).", e);
+ }
+ }
+
+ /**
+ * Serializes the message and writes it to {@code output}. This is just a
+ * trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public final void writeTo(OutputStream output) throws IOException {
+ CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ /** Get the number of bytes required to encode this set. */
+ public int getSerializedSize() {
+ int result = 0;
+ for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ result += entry.getValue().getSerializedSize(entry.getKey());
+ }
+ return result;
+ }
+
+ /**
+ * Serializes the set and writes it to {@code output} using
+ * {@code MessageSet} wire format.
+ */
+ public void writeAsMessageSetTo(CodedOutputStream output)
+ throws IOException {
+ for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ entry.getValue().writeAsMessageSetExtensionTo(
+ entry.getKey(), output);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this set using
+ * {@code MessageSet} wire format.
+ */
+ public int getSerializedSizeAsMessageSet() {
+ int result = 0;
+ for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ result += entry.getValue().getSerializedSizeAsMessageSetExtension(
+ entry.getKey());
+ }
+ return result;
+ }
+
+ /** Parse an {@code UnknownFieldSet} from the given input stream. */
+ static public UnknownFieldSet parseFrom(CodedInputStream input)
+ throws IOException {
+ return newBuilder().mergeFrom(input).build();
+ }
+
+ /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+ public static UnknownFieldSet parseFrom(ByteString data)
+ throws InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).build();
+ }
+
+ /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+ public static UnknownFieldSet parseFrom(byte[] data)
+ throws InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).build();
+ }
+
+ /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
+ public static UnknownFieldSet parseFrom(InputStream input)
+ throws IOException {
+ return newBuilder().mergeFrom(input).build();
+ }
+
+ /**
+ * Builder for {@link UnknownFieldSet}s.
+ *
+ * <p>Note that this class maintains {@link Field.Builder}s for all fields
+ * in the set. Thus, adding one element to an existing {@link Field} does not
+ * require making a copy. This is important for efficient parsing of
+ * unknown repeated fields. However, it implies that {@link Field}s cannot
+ * be constructed independently, nor can two {@link UnknownFieldSet}s share
+ * the same {@code Field} object.
+ *
+ * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
+ */
+ public static final class Builder {
+ private Builder() {}
+ private Map<Integer, Field> fields = new TreeMap<Integer, Field>();
+
+ // Optimization: We keep around a builder for the last field that was
+ // modified so that we can efficiently add to it multiple times in a
+ // row (important when parsing an unknown repeated field).
+ int lastFieldNumber = 0;
+ Field.Builder lastField = null;
+
+ /**
+ * Get a field builder for the given field number which includes any
+ * values that already exist.
+ */
+ private Field.Builder getFieldBuilder(int number) {
+ if (lastField != null) {
+ if (number == lastFieldNumber) {
+ return lastField;
+ }
+ // Note: addField() will reset lastField and lastFieldNumber.
+ addField(lastFieldNumber, lastField.build());
+ }
+ if (number == 0) {
+ return null;
+ } else {
+ Field existing = fields.get(number);
+ lastFieldNumber = number;
+ lastField = Field.newBuilder();
+ if (existing != null) {
+ lastField.mergeFrom(existing);
+ }
+ return lastField;
+ }
+ }
+
+ /**
+ * Build the {@link UnknownFieldSet} and return it.
+ *
+ * <p>Once {@code build()} has been called, the {@code Builder} will no
+ * longer be usable. Calling any method after {@code build()} will throw
+ * {@code NullPointerException}.
+ */
+ public UnknownFieldSet build() {
+ getFieldBuilder(0); // Force lastField to be built.
+ UnknownFieldSet result;
+ if (fields.isEmpty()) {
+ result = getDefaultInstance();
+ } else {
+ result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
+ }
+ fields = null;
+ return result;
+ }
+
+ /** Reset the builder to an empty set. */
+ public Builder clear() {
+ fields = new TreeMap<Integer, Field>();
+ lastFieldNumber = 0;
+ lastField = null;
+ return this;
+ }
+
+ /**
+ * Merge the fields from {@code other} into this set. If a field number
+ * exists in both sets, {@code other}'s values for that field will be
+ * appended to the values in this set.
+ */
+ public Builder mergeFrom(UnknownFieldSet other) {
+ if (other != getDefaultInstance()) {
+ for (Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
+ mergeField(entry.getKey(), entry.getValue());
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Add a field to the {@code UnknownFieldSet}. If a field with the same
+ * number already exists, the two are merged.
+ */
+ public Builder mergeField(int number, Field field) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ if (hasField(number)) {
+ getFieldBuilder(number).mergeFrom(field);
+ } else {
+ // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
+ // in this case, but that would create a copy of the Field object.
+ // We'd rather reuse the one passed to us, so call addField() instead.
+ addField(number, field);
+ }
+ return this;
+ }
+
+ /**
+ * Convenience method for merging a new field containing a single varint
+ * value. This is used in particular when an unknown enum value is
+ * encountered.
+ */
+ public Builder mergeVarintField(int number, int value) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ getFieldBuilder(number).addVarint(value);
+ return this;
+ }
+
+ /** Check if the given field number is present in the set. */
+ public boolean hasField(int number) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ return number == lastFieldNumber || fields.containsKey(number);
+ }
+
+ /**
+ * Add a field to the {@code UnknownFieldSet}. If a field with the same
+ * number already exists, it is removed.
+ */
+ public Builder addField(int number, Field field) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ if (lastField != null && lastFieldNumber == number) {
+ // Discard this.
+ lastField = null;
+ lastFieldNumber = 0;
+ }
+ fields.put(number, field);
+ return this;
+ }
+
+ /**
+ * Get all present {@code Field}s as an immutable {@code Map}. If more
+ * fields are added, the changes may or may not be reflected in this map.
+ */
+ public Map<Integer, Field> asMap() {
+ getFieldBuilder(0); // Force lastField to be built.
+ return Collections.unmodifiableMap(fields);
+ }
+
+ /**
+ * Parse an entire message from {@code input} and merge its fields into
+ * this set.
+ */
+ public Builder mergeFrom(CodedInputStream input) throws IOException {
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0 || !mergeFieldFrom(tag, input)) {
+ break;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Parse a single field from {@code input} and merge it into this set.
+ * @param tag The field's tag number, which was already parsed.
+ * @return {@code false} if the tag is an engroup tag.
+ */
+ public boolean mergeFieldFrom(int tag, CodedInputStream input)
+ throws IOException {
+ int number = WireFormat.getTagFieldNumber(tag);
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ getFieldBuilder(number).addVarint(input.readInt32());
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ getFieldBuilder(number).addFixed64(input.readFixed64());
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ getFieldBuilder(number).addLengthDelimited(input.readBytes());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP: {
+ UnknownFieldSet.Builder subBuilder = UnknownFieldSet.newBuilder();
+ input.readUnknownGroup(number, subBuilder);
+ getFieldBuilder(number).addGroup(subBuilder.build());
+ return true;
+ }
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ getFieldBuilder(number).addFixed32(input.readFixed32());
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(ByteString data)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = data.newCodedInput();
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(byte[] data)
+ throws InvalidProtocolBufferException {
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(InputStream input) throws IOException {
+ CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput);
+ codedInput.checkLastTagWas(0);
+ return this;
+ }
+ }
+
+ /**
+ * Represents a single field in an {@code UnknownFieldSet}.
+ *
+ * <p>A {@code Field} consists of five lists of values. The lists correspond
+ * to the five "wire types" used in the protocol buffer binary format.
+ * The wire type of each field can be determined from the encoded form alone,
+ * without knowing the field's declared type. So, we are able to parse
+ * unknown values at least this far and separate them. Normally, only one
+ * of the five lists will contain any values, since it is impossible to
+ * define a valid message type that declares two different types for the
+ * same field number. However, the code is designed to allow for the case
+ * where the same unknown field number is encountered using multiple different
+ * wire types.
+ *
+ * <p>{@code Field} is an immutable class. To construct one, you must use a
+ * {@link Field.Builder}.
+ *
+ * @see UnknownFieldSet
+ */
+ public static final class Field {
+ private Field() {}
+
+ /** Construct a new {@link Builder}. */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Construct a new {@link Builder} and initialize it to a copy of
+ * {@code copyFrom}.
+ */
+ public static Builder newBuilder(Field copyFrom) {
+ return new Builder().mergeFrom(copyFrom);
+ }
+
+ /** Get an empty {@code Field}. */
+ public static Field getDefaultInstance() {
+ return defaultInstance;
+ }
+ private static Field defaultInstance = newBuilder().build();
+
+ /** Get the list of varint values for this field. */
+ public List<Long> getVarintList() { return varint; }
+
+ /** Get the list of fixed32 values for this field. */
+ public List<Integer> getFixed32List() { return fixed32; }
+
+ /** Get the list of fixed64 values for this field. */
+ public List<Long> getFixed64List() { return fixed64; }
+
+ /** Get the list of length-delimited values for this field. */
+ public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
+
+ /**
+ * Get the list of embedded group values for this field. These are
+ * represented using {@link UnknownFieldSet}s rather than {@link Message}s
+ * since the group's type is presumably unknown.
+ */
+ public List<UnknownFieldSet> getGroupList() { return group; }
+
+ /**
+ * Serializes the field, including field number, and writes it to
+ * {@code output}.
+ */
+ public void writeTo(int fieldNumber, CodedOutputStream output)
+ throws IOException {
+ for (long value : varint) {
+ output.writeUInt64(fieldNumber, value);
+ }
+ for (int value : fixed32) {
+ output.writeFixed32(fieldNumber, value);
+ }
+ for (long value : fixed64) {
+ output.writeFixed64(fieldNumber, value);
+ }
+ for (ByteString value : lengthDelimited) {
+ output.writeBytes(fieldNumber, value);
+ }
+ for (UnknownFieldSet value : group) {
+ output.writeUnknownGroup(fieldNumber, value);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this field, including field
+ * number.
+ */
+ public int getSerializedSize(int fieldNumber) {
+ int result = 0;
+ for (long value : varint) {
+ result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
+ }
+ for (int value : fixed32) {
+ result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
+ }
+ for (long value : fixed64) {
+ result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
+ }
+ for (ByteString value : lengthDelimited) {
+ result += CodedOutputStream.computeBytesSize(fieldNumber, value);
+ }
+ for (UnknownFieldSet value : group) {
+ result += CodedOutputStream.computeUnknownGroupSize(fieldNumber, value);
+ }
+ return result;
+ }
+
+ /**
+ * Serializes the field, including field number, and writes it to
+ * {@code output}, using {@code MessageSet} wire format.
+ */
+ public void writeAsMessageSetExtensionTo(
+ int fieldNumber,
+ CodedOutputStream output)
+ throws IOException {
+ for (ByteString value : lengthDelimited) {
+ output.writeRawMessageSetExtension(fieldNumber, value);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this field, including field
+ * number, using {@code MessageSet} wire format.
+ */
+ public int getSerializedSizeAsMessageSetExtension(int fieldNumber) {
+ int result = 0;
+ for (ByteString value : lengthDelimited) {
+ result += CodedOutputStream.computeRawMessageSetExtensionSize(
+ fieldNumber, value);
+ }
+ return result;
+ }
+
+ private List<Long> varint;
+ private List<Integer> fixed32;
+ private List<Long> fixed64;
+ private List<ByteString> lengthDelimited;
+ private List<UnknownFieldSet> group;
+
+ /**
+ * Used to build a {@link Field} within an {@link UnknownFieldSet}.
+ *
+ * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
+ */
+ public static final class Builder {
+ private Builder() {}
+ private Field result = new Field();
+
+ /**
+ * Build the field. After {@code build()} has been called, the
+ * {@code Builder} is no longer usable. Calling any other method will
+ * throw a {@code NullPointerException}.
+ */
+ public Field build() {
+ if (result.varint == null) {
+ result.varint = Collections.emptyList();
+ } else {
+ result.varint = Collections.unmodifiableList(result.varint);
+ }
+ if (result.fixed32 == null) {
+ result.fixed32 = Collections.emptyList();
+ } else {
+ result.fixed32 = Collections.unmodifiableList(result.fixed32);
+ }
+ if (result.fixed64 == null) {
+ result.fixed64 = Collections.emptyList();
+ } else {
+ result.fixed64 = Collections.unmodifiableList(result.fixed64);
+ }
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = Collections.emptyList();
+ } else {
+ result.lengthDelimited =
+ Collections.unmodifiableList(result.lengthDelimited);
+ }
+ if (result.group == null) {
+ result.group = Collections.emptyList();
+ } else {
+ result.group = Collections.unmodifiableList(result.group);
+ }
+
+ Field returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ /** Discard the field's contents. */
+ public Builder clear() {
+ result = new Field();
+ return this;
+ }
+
+ /**
+ * Merge the values in {@code other} into this field. For each list
+ * of values, {@code other}'s values are append to the ones in this
+ * field.
+ */
+ public Builder mergeFrom(Field other) {
+ if (!other.varint.isEmpty()) {
+ if (result.varint == null) {
+ result.varint = new ArrayList<Long>();
+ }
+ result.varint.addAll(other.varint);
+ }
+ if (!other.fixed32.isEmpty()) {
+ if (result.fixed32 == null) {
+ result.fixed32 = new ArrayList<Integer>();
+ }
+ result.fixed32.addAll(other.fixed32);
+ }
+ if (!other.fixed64.isEmpty()) {
+ if (result.fixed64 == null) {
+ result.fixed64 = new ArrayList<Long>();
+ }
+ result.fixed64.addAll(other.fixed64);
+ }
+ if (!other.lengthDelimited.isEmpty()) {
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = new ArrayList<ByteString>();
+ }
+ result.lengthDelimited.addAll(other.lengthDelimited);
+ }
+ if (!other.group.isEmpty()) {
+ if (result.group == null) {
+ result.group = new ArrayList<UnknownFieldSet>();
+ }
+ result.group.addAll(other.group);
+ }
+ return this;
+ }
+
+ /** Add a varint value. */
+ public Builder addVarint(long value) {
+ if (result.varint == null) {
+ result.varint = new ArrayList<Long>();
+ }
+ result.varint.add(value);
+ return this;
+ }
+
+ /** Add a fixed32 value. */
+ public Builder addFixed32(int value) {
+ if (result.fixed32 == null) {
+ result.fixed32 = new ArrayList<Integer>();
+ }
+ result.fixed32.add(value);
+ return this;
+ }
+
+ /** Add a fixed64 value. */
+ public Builder addFixed64(long value) {
+ if (result.fixed64 == null) {
+ result.fixed64 = new ArrayList<Long>();
+ }
+ result.fixed64.add(value);
+ return this;
+ }
+
+ /** Add a length-delimited value. */
+ public Builder addLengthDelimited(ByteString value) {
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = new ArrayList<ByteString>();
+ }
+ result.lengthDelimited.add(value);
+ return this;
+ }
+
+ /** Add an embedded group. */
+ public Builder addGroup(UnknownFieldSet value) {
+ if (result.group == null) {
+ result.group = new ArrayList<UnknownFieldSet>();
+ }
+ result.group.add(value);
+ return this;
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java
new file mode 100644
index 00000000..31bfd402
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/WireFormat.java
@@ -0,0 +1,99 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations. It is public only because those generated messages
+ * do not reside in the {@code protocol2} package. Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormat {
+ // Do not allow instantiation.
+ private WireFormat() {}
+
+ static final int WIRETYPE_VARINT = 0;
+ static final int WIRETYPE_FIXED64 = 1;
+ static final int WIRETYPE_LENGTH_DELIMITED = 2;
+ static final int WIRETYPE_START_GROUP = 3;
+ static final int WIRETYPE_END_GROUP = 4;
+ static final int WIRETYPE_FIXED32 = 5;
+
+ static final int TAG_TYPE_BITS = 3;
+ static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+ /** Given a tag value, determines the wire type (the lower 3 bits). */
+ static int getTagWireType(int tag) {
+ return tag & TAG_TYPE_MASK;
+ }
+
+ /** Given a tag value, determines the field number (the upper 29 bits). */
+ public static int getTagFieldNumber(int tag) {
+ return tag >>> TAG_TYPE_BITS;
+ }
+
+ /** Makes a tag value given a field number and wire type. */
+ static int makeTag(int fieldNumber, int wireType) {
+ return (fieldNumber << TAG_TYPE_BITS) | wireType;
+ }
+
+ static int getWireFormatForFieldType(Descriptors.FieldDescriptor.Type type) {
+ switch (type) {
+ case DOUBLE : return WIRETYPE_FIXED64;
+ case FLOAT : return WIRETYPE_FIXED32;
+ case INT64 : return WIRETYPE_VARINT;
+ case UINT64 : return WIRETYPE_VARINT;
+ case INT32 : return WIRETYPE_VARINT;
+ case FIXED64 : return WIRETYPE_FIXED64;
+ case FIXED32 : return WIRETYPE_FIXED32;
+ case BOOL : return WIRETYPE_VARINT;
+ case STRING : return WIRETYPE_LENGTH_DELIMITED;
+ case GROUP : return WIRETYPE_START_GROUP;
+ case MESSAGE : return WIRETYPE_LENGTH_DELIMITED;
+ case BYTES : return WIRETYPE_LENGTH_DELIMITED;
+ case UINT32 : return WIRETYPE_VARINT;
+ case ENUM : return WIRETYPE_VARINT;
+ case SFIXED32: return WIRETYPE_FIXED32;
+ case SFIXED64: return WIRETYPE_FIXED64;
+ case SINT32 : return WIRETYPE_VARINT;
+ case SINT64 : return WIRETYPE_VARINT;
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
+
+ // Field numbers for feilds in MessageSet wire format.
+ static final int MESSAGE_SET_ITEM = 1;
+ static final int MESSAGE_SET_TYPE_ID = 2;
+ static final int MESSAGE_SET_MESSAGE = 3;
+
+ // Tag numbers.
+ static final int MESSAGE_SET_ITEM_TAG =
+ makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
+ static final int MESSAGE_SET_ITEM_END_TAG =
+ makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
+ static final int MESSAGE_SET_TYPE_ID_TAG =
+ makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
+ static final int MESSAGE_SET_MESSAGE_TAG =
+ makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+}
diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
new file mode 100644
index 00000000..bbb88b86
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -0,0 +1,362 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+/**
+ * Unit test for {@link AbstractMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class AbstractMessageTest extends TestCase {
+ /**
+ * Extends AbstractMessage and wraps some other message object. The methods
+ * of the Message interface which aren't explicitly implemented by
+ * AbstractMessage are forwarded to the wrapped object. This allows us to
+ * test that AbstractMessage's implementations work even if the wrapped
+ * object does not use them.
+ */
+ private static class AbstractMessageWrapper extends AbstractMessage {
+ private final Message wrappedMessage;
+
+ public AbstractMessageWrapper(Message wrappedMessage) {
+ this.wrappedMessage = wrappedMessage;
+ }
+
+ public Descriptors.Descriptor getDescriptorForType() {
+ return wrappedMessage.getDescriptorForType();
+ }
+ public AbstractMessageWrapper getDefaultInstanceForType() {
+ return new AbstractMessageWrapper(
+ wrappedMessage.getDefaultInstanceForType());
+ }
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return wrappedMessage.getAllFields();
+ }
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.hasField(field);
+ }
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.getField(field);
+ }
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.getRepeatedFieldCount(field);
+ }
+ public Object getRepeatedField(
+ Descriptors.FieldDescriptor field, int index) {
+ return wrappedMessage.getRepeatedField(field, index);
+ }
+ public UnknownFieldSet getUnknownFields() {
+ return wrappedMessage.getUnknownFields();
+ }
+ public Builder newBuilderForType() {
+ return new Builder(wrappedMessage.newBuilderForType());
+ }
+
+ static class Builder extends AbstractMessage.Builder<Builder> {
+ private final Message.Builder wrappedBuilder;
+
+ public Builder(Message.Builder wrappedBuilder) {
+ this.wrappedBuilder = wrappedBuilder;
+ }
+
+ public AbstractMessageWrapper build() {
+ return new AbstractMessageWrapper(wrappedBuilder.build());
+ }
+ public AbstractMessageWrapper buildPartial() {
+ return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
+ }
+ public Builder clone() {
+ return new Builder(wrappedBuilder.clone());
+ }
+ public boolean isInitialized() {
+ return clone().buildPartial().isInitialized();
+ }
+ public Descriptors.Descriptor getDescriptorForType() {
+ return wrappedBuilder.getDescriptorForType();
+ }
+ public AbstractMessageWrapper getDefaultInstanceForType() {
+ return new AbstractMessageWrapper(
+ wrappedBuilder.getDefaultInstanceForType());
+ }
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return wrappedBuilder.getAllFields();
+ }
+ public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
+ return new Builder(wrappedBuilder.newBuilderForField(field));
+ }
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.hasField(field);
+ }
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.getField(field);
+ }
+ public Builder setField(Descriptors.FieldDescriptor field, Object value) {
+ wrappedBuilder.setField(field, value);
+ return this;
+ }
+ public Builder clearField(Descriptors.FieldDescriptor field) {
+ wrappedBuilder.clearField(field);
+ return this;
+ }
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.getRepeatedFieldCount(field);
+ }
+ public Object getRepeatedField(
+ Descriptors.FieldDescriptor field, int index) {
+ return wrappedBuilder.getRepeatedField(field, index);
+ }
+ public Builder setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value) {
+ wrappedBuilder.setRepeatedField(field, index, value);
+ return this;
+ }
+ public Builder addRepeatedField(
+ Descriptors.FieldDescriptor field, Object value) {
+ wrappedBuilder.addRepeatedField(field, value);
+ return this;
+ }
+ public UnknownFieldSet getUnknownFields() {
+ return wrappedBuilder.getUnknownFields();
+ }
+ public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+ wrappedBuilder.setUnknownFields(unknownFields);
+ return this;
+ }
+ }
+ }
+
+ // =================================================================
+
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+
+ public void testClear() throws Exception {
+ AbstractMessageWrapper message =
+ new AbstractMessageWrapper.Builder(
+ TestAllTypes.newBuilder(TestUtil.getAllSet()))
+ .clear().build();
+ TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testCopy() throws Exception {
+ AbstractMessageWrapper message =
+ new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
+ .mergeFrom(TestUtil.getAllSet()).build();
+ TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testSerializedSize() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+ Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+ assertEquals(message.getSerializedSize(),
+ abstractMessage.getSerializedSize());
+ }
+
+ public void testSerialization() throws Exception {
+ Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+ TestUtil.assertAllFieldsSet(
+ TestAllTypes.parseFrom(abstractMessage.toByteString()));
+
+ assertEquals(TestUtil.getAllSet().toByteString(),
+ abstractMessage.toByteString());
+ }
+
+ public void testParsing() throws Exception {
+ AbstractMessageWrapper.Builder builder =
+ new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
+ AbstractMessageWrapper message =
+ builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
+ TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testOptimizedForSize() throws Exception {
+ // We're mostly only checking that this class was compiled successfully.
+ TestOptimizedForSize message =
+ TestOptimizedForSize.newBuilder().setI(1).build();
+ message = TestOptimizedForSize.parseFrom(message.toByteString());
+ assertEquals(2, message.getSerializedSize());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for isInitialized().
+
+ private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ TestRequired.getDefaultInstance();
+ private static final TestRequired TEST_REQUIRED_INITIALIZED =
+ TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+ public void testIsInitialized() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+ AbstractMessageWrapper.Builder abstractBuilder =
+ new AbstractMessageWrapper.Builder(builder);
+
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setA(1);
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setB(1);
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setC(1);
+ assertTrue(abstractBuilder.isInitialized());
+ }
+
+ public void testForeignIsInitialized() throws Exception {
+ TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+ AbstractMessageWrapper.Builder abstractBuilder =
+ new AbstractMessageWrapper.Builder(builder);
+
+ assertTrue(abstractBuilder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(abstractBuilder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+ assertTrue(abstractBuilder.isInitialized());
+
+ builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(abstractBuilder.isInitialized());
+
+ builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(abstractBuilder.isInitialized());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for mergeFrom
+
+ static final TestAllTypes MERGE_SOURCE =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedString("bar")
+ .build();
+
+ static final TestAllTypes MERGE_DEST =
+ TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+ .addRepeatedString("qux")
+ .build();
+
+ static final String MERGE_RESULT_TEXT =
+ "optional_int32: 1\n" +
+ "optional_int64: 2\n" +
+ "optional_string: \"foo\"\n" +
+ "optional_foreign_message {\n" +
+ " c: 3\n" +
+ "}\n" +
+ "repeated_string: \"qux\"\n" +
+ "repeated_string: \"bar\"\n";
+
+ public void testMergeFrom() throws Exception {
+ AbstractMessageWrapper result =
+ new AbstractMessageWrapper.Builder(
+ TestAllTypes.newBuilder(MERGE_DEST))
+ .mergeFrom(MERGE_SOURCE).build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for equals and hashCode
+
+ public void testEqualsAndHashCode() {
+ TestAllTypes a = TestUtil.getAllSet();
+ TestAllTypes b = TestAllTypes.newBuilder().build();
+ TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
+ TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
+ TestAllExtensions e = TestUtil.getAllExtensionsSet();
+ TestAllExtensions f = TestAllExtensions.newBuilder(e)
+ .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
+
+ checkEqualsIsConsistent(a);
+ checkEqualsIsConsistent(b);
+ checkEqualsIsConsistent(c);
+ checkEqualsIsConsistent(d);
+ checkEqualsIsConsistent(e);
+ checkEqualsIsConsistent(f);
+
+ checkNotEqual(a, b);
+ checkNotEqual(a, c);
+ checkNotEqual(a, d);
+ checkNotEqual(a, e);
+ checkNotEqual(a, f);
+
+ checkNotEqual(b, c);
+ checkNotEqual(b, d);
+ checkNotEqual(b, e);
+ checkNotEqual(b, f);
+
+ checkNotEqual(c, d);
+ checkNotEqual(c, e);
+ checkNotEqual(c, f);
+
+ checkNotEqual(d, e);
+ checkNotEqual(d, f);
+
+ checkNotEqual(e, f);
+ }
+
+ /**
+ * Asserts that the given protos are equal and have the same hash code.
+ */
+ private void checkEqualsIsConsistent(Message message) {
+ // Object should be equal to itself.
+ assertEquals(message, message);
+
+ // Object should be equal to a dynamic copy of itself.
+ DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
+ assertEquals(message, dynamic);
+ assertEquals(dynamic, message);
+ assertEquals(dynamic.hashCode(), message.hashCode());
+ }
+
+ /**
+ * Asserts that the given protos are not equal and have different hash codes.
+ *
+ * @warning It's valid for non-equal objects to have the same hash code, so
+ * this test is stricter than it needs to be. However, this should happen
+ * relatively rarely.
+ */
+ private void checkNotEqual(Message m1, Message m2) {
+ String equalsError = String.format("%s should not be equal to %s", m1, m2);
+ assertFalse(equalsError, m1.equals(m2));
+ assertFalse(equalsError, m2.equals(m1));
+
+ assertFalse(
+ String.format("%s should have a different hash code from %s", m1, m2),
+ m1.hashCode() == m2.hashCode());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
new file mode 100644
index 00000000..b34e56f0
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -0,0 +1,401 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRecursiveMessage;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Unit test for {@link CodedInputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedInputStreamTest extends TestCase {
+ /**
+ * Helper to construct a byte array from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private byte[] bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return bytes;
+ }
+
+ /**
+ * An InputStream which limits the number of bytes it reads at a time.
+ * We use this to make sure that CodedInputStream doesn't screw up when
+ * reading in small blocks.
+ */
+ private static final class SmallBlockInputStream extends FilterInputStream {
+ private final int blockSize;
+
+ public SmallBlockInputStream(byte[] data, int blockSize) {
+ this(new ByteArrayInputStream(data), blockSize);
+ }
+
+ public SmallBlockInputStream(InputStream in, int blockSize) {
+ super(in);
+ this.blockSize = blockSize;
+ }
+
+ public int read(byte[] b) throws IOException {
+ return super.read(b, 0, Math.min(b.length, blockSize));
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ return super.read(b, off, Math.min(len, blockSize));
+ }
+ }
+
+ /**
+ * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+ * checks that the result matches the given value.
+ */
+ private void assertReadVarint(byte[] data, long value) throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals((int)value, input.readRawVarint32());
+
+ input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawVarint64());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals((int)value, input.readRawVarint32());
+
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawVarint64());
+ }
+ }
+
+ /**
+ * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+ * expects them to fail with an InvalidProtocolBufferException whose
+ * description matches the given one.
+ */
+ private void assertReadVarintFailure(
+ InvalidProtocolBufferException expected, byte[] data)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ try {
+ input.readRawVarint32();
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+
+ input = CodedInputStream.newInstance(data);
+ try {
+ input.readRawVarint64();
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+ }
+
+ /** Tests readRawVarint32() and readRawVarint64(). */
+ public void testReadVarint() throws Exception {
+ assertReadVarint(bytes(0x00), 0);
+ assertReadVarint(bytes(0x01), 1);
+ assertReadVarint(bytes(0x7f), 127);
+ // 14882
+ assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+ // 2961488830
+ assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x0bL << 28));
+
+ // 64-bit
+ // 7256456126
+ assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x1bL << 28));
+ // 41256202580718336
+ assertReadVarint(
+ bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+ (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ // 11964378330978735131
+ assertReadVarint(
+ bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+ (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+ (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+
+ // Failures
+ assertReadVarintFailure(
+ InvalidProtocolBufferException.malformedVarint(),
+ bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x00));
+ assertReadVarintFailure(
+ InvalidProtocolBufferException.truncatedMessage(),
+ bytes(0x80));
+ }
+
+ /**
+ * Parses the given bytes using readRawLittleEndian32() and checks
+ * that the result matches the given value.
+ */
+ private void assertReadLittleEndian32(byte[] data, int value)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawLittleEndian32());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawLittleEndian32());
+ }
+ }
+
+ /**
+ * Parses the given bytes using readRawLittleEndian64() and checks
+ * that the result matches the given value.
+ */
+ private void assertReadLittleEndian64(byte[] data, long value)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawLittleEndian64());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawLittleEndian64());
+ }
+ }
+
+ /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
+ public void testReadLittleEndian() throws Exception {
+ assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+ assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+ assertReadLittleEndian64(
+ bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+ 0x123456789abcdef0L);
+ assertReadLittleEndian64(
+ bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+ 0x9abcdef012345678L);
+ }
+
+ /** Test decodeZigZag32() and decodeZigZag64(). */
+ public void testDecodeZigZag() throws Exception {
+ assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+ assertEquals(-1, CodedInputStream.decodeZigZag32(1));
+ assertEquals( 1, CodedInputStream.decodeZigZag32(2));
+ assertEquals(-2, CodedInputStream.decodeZigZag32(3));
+ assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
+ assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
+ assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
+ assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
+
+ assertEquals( 0, CodedInputStream.decodeZigZag64(0));
+ assertEquals(-1, CodedInputStream.decodeZigZag64(1));
+ assertEquals( 1, CodedInputStream.decodeZigZag64(2));
+ assertEquals(-2, CodedInputStream.decodeZigZag64(3));
+ assertEquals(0x000000003FFFFFFFL,
+ CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
+ assertEquals(0xFFFFFFFFC0000000L,
+ CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
+ assertEquals(0x000000007FFFFFFFL,
+ CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
+ assertEquals(0xFFFFFFFF80000000L,
+ CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
+ assertEquals(0x7FFFFFFFFFFFFFFFL,
+ CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+ assertEquals(0x8000000000000000L,
+ CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+ }
+
+ /** Tests reading and parsing a whole message with every field type. */
+ public void testReadWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ byte[] rawBytes = message.toByteArray();
+ assertEquals(rawBytes.length, message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+ TestUtil.assertAllFieldsSet(message2);
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+ message2 = TestAllTypes.parseFrom(
+ new SmallBlockInputStream(rawBytes, blockSize));
+ TestUtil.assertAllFieldsSet(message2);
+ }
+ }
+
+ /** Tests skipField(). */
+ public void testSkipWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+ byte[] rawBytes = message.toByteArray();
+
+ // Create two parallel inputs. Parse one as unknown fields while using
+ // skipField() to skip each field on the other. Expect the same tags.
+ CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
+ CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+ UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
+
+ while (true) {
+ int tag = input1.readTag();
+ assertEquals(tag, input2.readTag());
+ if (tag == 0) {
+ break;
+ }
+ unknownFields.mergeFieldFrom(tag, input1);
+ input2.skipField(tag);
+ }
+ }
+
+ public void testReadHugeBlob() throws Exception {
+ // Allocate and initialize a 1MB blob.
+ byte[] blob = new byte[1 << 20];
+ for (int i = 0; i < blob.length; i++) {
+ blob[i] = (byte)i;
+ }
+
+ // Make a message containing it.
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ builder.setOptionalBytes(ByteString.copyFrom(blob));
+ TestAllTypes message = builder.build();
+
+ // Serialize and parse it. Make sure to parse from an InputStream, not
+ // directly from a ByteString, so that CodedInputStream uses buffered
+ // reading.
+ TestAllTypes message2 =
+ TestAllTypes.parseFrom(message.toByteString().newInput());
+
+ assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
+
+ // Make sure all the other fields were parsed correctly.
+ TestAllTypes message3 = TestAllTypes.newBuilder(message2)
+ .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+ .build();
+ TestUtil.assertAllFieldsSet(message3);
+ }
+
+ public void testReadMaliciouslyLargeBlob() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(0x7FFFFFFF);
+ output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
+ output.flush();
+
+ CodedInputStream input = rawOutput.toByteString().newCodedInput();
+ assertEquals(tag, input.readTag());
+
+ try {
+ input.readBytes();
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ private TestRecursiveMessage makeRecursiveMessage(int depth) {
+ if (depth == 0) {
+ return TestRecursiveMessage.newBuilder().setI(5).build();
+ } else {
+ return TestRecursiveMessage.newBuilder()
+ .setA(makeRecursiveMessage(depth - 1)).build();
+ }
+ }
+
+ private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+ if (depth == 0) {
+ assertFalse(message.hasA());
+ assertEquals(5, message.getI());
+ } else {
+ assertTrue(message.hasA());
+ assertMessageDepth(message.getA(), depth - 1);
+ }
+ }
+
+ public void testMaliciousRecursion() throws Exception {
+ ByteString data64 = makeRecursiveMessage(64).toByteString();
+ ByteString data65 = makeRecursiveMessage(65).toByteString();
+
+ assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64);
+
+ try {
+ TestRecursiveMessage.parseFrom(data65);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+
+ CodedInputStream input = data64.newCodedInput();
+ input.setRecursionLimit(8);
+ try {
+ TestRecursiveMessage.parseFrom(input);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ public void testSizeLimit() throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(
+ TestUtil.getAllSet().toByteString().newInput());
+ input.setSizeLimit(16);
+
+ try {
+ TestAllTypes.parseFrom(input);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ /**
+ * Tests that if we read an string that contains invalid UTF-8, no exception
+ * is thrown. Instead, the invalid bytes are replaced with the Unicode
+ * "replacement character" U+FFFD.
+ */
+ public void testReadInvalidUtf8() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[] { (byte)0x80 });
+ output.flush();
+
+ CodedInputStream input = rawOutput.toByteString().newCodedInput();
+ assertEquals(tag, input.readTag());
+ String text = input.readString();
+ assertEquals(0xfffd, text.charAt(0));
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
new file mode 100644
index 00000000..7ee75534
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -0,0 +1,280 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for {@link CodedOutputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedOutputStreamTest extends TestCase {
+ /**
+ * Helper to construct a byte array from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private byte[] bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return bytes;
+ }
+
+ /** Arrays.asList() does not work with arrays of primitives. :( */
+ private List<Byte> toList(byte[] bytes) {
+ List<Byte> result = new ArrayList<Byte>();
+ for (byte b : bytes) {
+ result.add(b);
+ }
+ return result;
+ }
+
+ private void assertEqualBytes(byte[] a, byte[] b) {
+ assertEquals(toList(a), toList(b));
+ }
+
+ /**
+ * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+ * checks that the result matches the given bytes.
+ */
+ private void assertWriteVarint(byte[] data, long value) throws Exception {
+ // Only do 32-bit write if the value fits in 32 bits.
+ if ((value >>> 32) == 0) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint32((int) value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length,
+ CodedOutputStream.computeRawVarint32Size((int) value));
+ }
+
+ {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length,
+ CodedOutputStream.computeRawVarint64Size(value));
+ }
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ // Only do 32-bit write if the value fits in 32 bits.
+ if ((value >>> 32) == 0) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawVarint32((int) value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+
+ {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawVarint64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+ }
+
+ /** Tests writeRawVarint32() and writeRawVarint64(). */
+ public void testWriteVarint() throws Exception {
+ assertWriteVarint(bytes(0x00), 0);
+ assertWriteVarint(bytes(0x01), 1);
+ assertWriteVarint(bytes(0x7f), 127);
+ // 14882
+ assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+ // 2961488830
+ assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x0bL << 28));
+
+ // 64-bit
+ // 7256456126
+ assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x1bL << 28));
+ // 41256202580718336
+ assertWriteVarint(
+ bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+ (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ // 11964378330978735131
+ assertWriteVarint(
+ bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+ (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+ (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian32() and checks
+ * that the result matches the given value.
+ */
+ private void assertWriteLittleEndian32(byte[] data, int value)
+ throws Exception {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawLittleEndian32(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ rawOutput = new ByteArrayOutputStream();
+ output = CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawLittleEndian32(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian64() and checks
+ * that the result matches the given value.
+ */
+ private void assertWriteLittleEndian64(byte[] data, long value)
+ throws Exception {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawLittleEndian64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ rawOutput = new ByteArrayOutputStream();
+ output = CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawLittleEndian64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+
+ /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
+ public void testWriteLittleEndian() throws Exception {
+ assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+ assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+ assertWriteLittleEndian64(
+ bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+ 0x123456789abcdef0L);
+ assertWriteLittleEndian64(
+ bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+ 0x9abcdef012345678L);
+ }
+
+ /** Test encodeZigZag32() and encodeZigZag64(). */
+ public void testEncodeZigZag() throws Exception {
+ assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
+ assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
+ assertEquals(2, CodedOutputStream.encodeZigZag32( 1));
+ assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
+ assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
+ assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
+ assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
+ assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
+
+ assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
+ assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
+ assertEquals(2, CodedOutputStream.encodeZigZag64( 1));
+ assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
+ assertEquals(0x000000007FFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
+ assertEquals(0x000000007FFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
+ assertEquals(0x00000000FFFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
+ assertEquals(0x00000000FFFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
+ assertEquals(0xFFFFFFFFFFFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
+ assertEquals(0xFFFFFFFFFFFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0x8000000000000000L));
+
+ // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1)
+ // were chosen semi-randomly via keyboard bashing.
+ assertEquals(0,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
+ assertEquals(1,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
+ assertEquals(-1,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
+ assertEquals(14927,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
+ assertEquals(-3612,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
+
+ assertEquals(0,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
+ assertEquals(1,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
+ assertEquals(-1,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
+ assertEquals(14927,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
+ assertEquals(-3612,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
+
+ assertEquals(856912304801416L,
+ CodedOutputStream.encodeZigZag64(
+ CodedInputStream.decodeZigZag64(
+ 856912304801416L)));
+ assertEquals(-75123905439571256L,
+ CodedOutputStream.encodeZigZag64(
+ CodedInputStream.decodeZigZag64(
+ -75123905439571256L)));
+ }
+
+ /** Tests writing a whole message with every field type. */
+ public void testWriteWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ byte[] rawBytes = message.toByteArray();
+ assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ message.writeTo(output);
+ output.flush();
+ assertEqualBytes(rawBytes, rawOutput.toByteArray());
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
new file mode 100644
index 00000000..98d6d01a
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -0,0 +1,313 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.ServiceDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+
+import com.google.protobuf.test.UnittestImport;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestService;
+
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Unit test for {@link Descriptors}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DescriptorsTest extends TestCase {
+ public void testFileDescriptor() throws Exception {
+ FileDescriptor file = UnittestProto.getDescriptor();
+
+ assertEquals("google/protobuf/unittest.proto", file.getName());
+ assertEquals("protobuf_unittest", file.getPackage());
+
+ assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
+ assertEquals("google/protobuf/unittest.proto",
+ file.toProto().getName());
+
+ assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
+ file.getDependencies());
+
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ assertEquals(messageType, file.getMessageTypes().get(0));
+ assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
+ assertNull(file.findMessageTypeByName("NoSuchType"));
+ assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
+ for (int i = 0; i < file.getMessageTypes().size(); i++) {
+ assertEquals(i, file.getMessageTypes().get(i).getIndex());
+ }
+
+ EnumDescriptor enumType = ForeignEnum.getDescriptor();
+ assertEquals(enumType, file.getEnumTypes().get(0));
+ assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
+ assertNull(file.findEnumTypeByName("NoSuchType"));
+ assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
+ assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
+ UnittestImport.getDescriptor().getEnumTypes());
+ for (int i = 0; i < file.getEnumTypes().size(); i++) {
+ assertEquals(i, file.getEnumTypes().get(i).getIndex());
+ }
+
+ ServiceDescriptor service = TestService.getDescriptor();
+ assertEquals(service, file.getServices().get(0));
+ assertEquals(service, file.findServiceByName("TestService"));
+ assertNull(file.findServiceByName("NoSuchType"));
+ assertNull(file.findServiceByName("protobuf_unittest.TestService"));
+ assertEquals(Collections.emptyList(),
+ UnittestImport.getDescriptor().getServices());
+ for (int i = 0; i < file.getServices().size(); i++) {
+ assertEquals(i, file.getServices().get(i).getIndex());
+ }
+
+ FieldDescriptor extension =
+ UnittestProto.optionalInt32Extension.getDescriptor();
+ assertEquals(extension, file.getExtensions().get(0));
+ assertEquals(extension,
+ file.findExtensionByName("optional_int32_extension"));
+ assertNull(file.findExtensionByName("no_such_ext"));
+ assertNull(file.findExtensionByName(
+ "protobuf_unittest.optional_int32_extension"));
+ assertEquals(Collections.emptyList(),
+ UnittestImport.getDescriptor().getExtensions());
+ for (int i = 0; i < file.getExtensions().size(); i++) {
+ assertEquals(i, file.getExtensions().get(i).getIndex());
+ }
+ }
+
+ public void testDescriptor() throws Exception {
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
+
+ assertEquals("TestAllTypes", messageType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
+ assertNull(messageType.getContainingType());
+ assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
+ messageType.getOptions());
+ assertEquals("TestAllTypes", messageType.toProto().getName());
+
+ assertEquals("NestedMessage", nestedType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
+ nestedType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+ assertEquals(messageType, nestedType.getContainingType());
+
+ FieldDescriptor field = messageType.getFields().get(0);
+ assertEquals("optional_int32", field.getName());
+ assertEquals(field, messageType.findFieldByName("optional_int32"));
+ assertNull(messageType.findFieldByName("no_such_field"));
+ assertEquals(field, messageType.findFieldByNumber(1));
+ assertNull(messageType.findFieldByNumber(571283));
+ for (int i = 0; i < messageType.getFields().size(); i++) {
+ assertEquals(i, messageType.getFields().get(i).getIndex());
+ }
+
+ assertEquals(nestedType, messageType.getNestedTypes().get(0));
+ assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
+ assertNull(messageType.findNestedTypeByName("NoSuchType"));
+ for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
+ assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
+ }
+
+ EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+ assertEquals(enumType, messageType.getEnumTypes().get(0));
+ assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
+ assertNull(messageType.findEnumTypeByName("NoSuchType"));
+ for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
+ assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
+ }
+ }
+
+ public void testFieldDescriptor() throws Exception {
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ FieldDescriptor primitiveField =
+ messageType.findFieldByName("optional_int32");
+ FieldDescriptor enumField =
+ messageType.findFieldByName("optional_nested_enum");
+ FieldDescriptor messageField =
+ messageType.findFieldByName("optional_foreign_message");
+ FieldDescriptor cordField =
+ messageType.findFieldByName("optional_cord");
+ FieldDescriptor extension =
+ UnittestProto.optionalInt32Extension.getDescriptor();
+ FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
+
+ assertEquals("optional_int32", primitiveField.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
+ primitiveField.getFullName());
+ assertEquals(1, primitiveField.getNumber());
+ assertEquals(messageType, primitiveField.getContainingType());
+ assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
+ assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
+ assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+ primitiveField.getOptions());
+ assertFalse(primitiveField.isExtension());
+ assertEquals("optional_int32", primitiveField.toProto().getName());
+
+ assertEquals("optional_nested_enum", enumField.getName());
+ assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
+ assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
+ assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
+ enumField.getEnumType());
+
+ assertEquals("optional_foreign_message", messageField.getName());
+ assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
+ assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
+ assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
+
+ assertEquals("optional_cord", cordField.getName());
+ assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
+ assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
+ cordField.getOptions().getCtype());
+
+ assertEquals("optional_int32_extension", extension.getName());
+ assertEquals("protobuf_unittest.optional_int32_extension",
+ extension.getFullName());
+ assertEquals(1, extension.getNumber());
+ assertEquals(TestAllExtensions.getDescriptor(),
+ extension.getContainingType());
+ assertEquals(UnittestProto.getDescriptor(), extension.getFile());
+ assertEquals(FieldDescriptor.Type.INT32, extension.getType());
+ assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+ extension.getOptions());
+ assertTrue(extension.isExtension());
+ assertEquals(null, extension.getExtensionScope());
+ assertEquals("optional_int32_extension", extension.toProto().getName());
+
+ assertEquals("single", nestedExtension.getName());
+ assertEquals("protobuf_unittest.TestRequired.single",
+ nestedExtension.getFullName());
+ assertEquals(TestRequired.getDescriptor(),
+ nestedExtension.getExtensionScope());
+ }
+
+ public void testFieldDescriptorLabel() throws Exception {
+ FieldDescriptor requiredField =
+ TestRequired.getDescriptor().findFieldByName("a");
+ FieldDescriptor optionalField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+ FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+
+ assertTrue(requiredField.isRequired());
+ assertFalse(requiredField.isRepeated());
+ assertFalse(optionalField.isRequired());
+ assertFalse(optionalField.isRepeated());
+ assertFalse(repeatedField.isRequired());
+ assertTrue(repeatedField.isRepeated());
+ }
+
+ public void testFieldDescriptorDefault() throws Exception {
+ Descriptor d = TestAllTypes.getDescriptor();
+ assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
+ assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
+ assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
+ assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
+
+ d = TestExtremeDefaultValues.getDescriptor();
+ assertEquals(
+ ByteString.copyFrom(
+ "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
+ d.findFieldByName("escaped_bytes").getDefaultValue());
+ assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
+ assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
+ }
+
+ public void testEnumDescriptor() throws Exception {
+ EnumDescriptor enumType = ForeignEnum.getDescriptor();
+ EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
+
+ assertEquals("ForeignEnum", enumType.getName());
+ assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
+ assertNull(enumType.getContainingType());
+ assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
+ enumType.getOptions());
+
+ assertEquals("NestedEnum", nestedType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
+ nestedType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+ assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
+
+ EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
+ assertEquals(value, enumType.getValues().get(0));
+ assertEquals("FOREIGN_FOO", value.getName());
+ assertEquals(4, value.getNumber());
+ assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
+ assertEquals(value, enumType.findValueByNumber(4));
+ assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
+ for (int i = 0; i < enumType.getValues().size(); i++) {
+ assertEquals(i, enumType.getValues().get(i).getIndex());
+ }
+ }
+
+ public void testServiceDescriptor() throws Exception {
+ ServiceDescriptor service = TestService.getDescriptor();
+
+ assertEquals("TestService", service.getName());
+ assertEquals("protobuf_unittest.TestService", service.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), service.getFile());
+
+ assertEquals(2, service.getMethods().size());
+
+ MethodDescriptor fooMethod = service.getMethods().get(0);
+ assertEquals("Foo", fooMethod.getName());
+ assertEquals(UnittestProto.FooRequest.getDescriptor(),
+ fooMethod.getInputType());
+ assertEquals(UnittestProto.FooResponse.getDescriptor(),
+ fooMethod.getOutputType());
+ assertEquals(fooMethod, service.findMethodByName("Foo"));
+
+ MethodDescriptor barMethod = service.getMethods().get(1);
+ assertEquals("Bar", barMethod.getName());
+ assertEquals(UnittestProto.BarRequest.getDescriptor(),
+ barMethod.getInputType());
+ assertEquals(UnittestProto.BarResponse.getDescriptor(),
+ barMethod.getOutputType());
+ assertEquals(barMethod, service.findMethodByName("Bar"));
+
+ assertNull(service.findMethodByName("NoSuchMethod"));
+
+ for (int i = 0; i < service.getMethods().size(); i++) {
+ assertEquals(i, service.getMethods().get(i).getIndex());
+ }
+ }
+
+}
diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
new file mode 100644
index 00000000..7a458981
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -0,0 +1,120 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which
+ * tests some {@link DynamicMessage} functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DynamicMessageTest extends TestCase {
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+
+ public void testDynamicMessageAccessors() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+ reflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testDynamicMessageExtensionAccessors() throws Exception {
+ // We don't need to extensively test DynamicMessage's handling of
+ // extensions because, frankly, it doesn't do anything special with them.
+ // It treats them just like any other fields.
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testDynamicMessageRepeatedSetters() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ Message message = builder.build();
+ reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+ }
+
+ public void testDynamicMessageDefaults() throws Exception {
+ reflectionTester.assertClearViaReflection(
+ DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
+ reflectionTester.assertClearViaReflection(
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
+ }
+
+ public void testDynamicMessageSerializedSize() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ Message.Builder dynamicBuilder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
+ Message dynamicMessage = dynamicBuilder.build();
+
+ assertEquals(message.getSerializedSize(),
+ dynamicMessage.getSerializedSize());
+ }
+
+ public void testDynamicMessageSerialization() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+
+ // In fact, the serialized forms should be exactly the same, byte-for-byte.
+ assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
+ }
+
+ public void testDynamicMessageParsing() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+
+ Message message2 =
+ DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
+ reflectionTester.assertAllFieldsSetViaReflection(message2);
+ }
+
+ public void testDynamicMessageCopy() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+
+ DynamicMessage copy = DynamicMessage.newBuilder(message).build();
+ reflectionTester.assertAllFieldsSetViaReflection(copy);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
new file mode 100644
index 00000000..30d73d28
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -0,0 +1,246 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.MultipleFilesTestProto;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.ServiceWithNoOuter;
+
+import junit.framework.TestCase;
+import java.util.Arrays;
+
+/**
+ * Unit test for generated messages and generated code. See also
+ * {@link MessageTest}, which tests some generated message functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class GeneratedMessageTest extends TestCase {
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ public void testDefaultInstance() throws Exception {
+ assertSame(TestAllTypes.getDefaultInstance(),
+ TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
+ assertSame(TestAllTypes.getDefaultInstance(),
+ TestAllTypes.newBuilder().getDefaultInstanceForType());
+ }
+
+ public void testAccessors() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertAllFieldsSet(message);
+ }
+
+ public void testRepeatedSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestUtil.modifyRepeatedFields(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertRepeatedFieldsModified(message);
+ }
+
+ public void testRepeatedAppend() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+ builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
+ builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+
+ ForeignMessage foreignMessage =
+ ForeignMessage.newBuilder().setC(12).build();
+ builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
+
+ TestAllTypes message = builder.build();
+ assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
+ assertEquals(message.getRepeatedForeignEnumList(),
+ Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+ assertEquals(1, message.getRepeatedForeignMessageCount());
+ assertEquals(12, message.getRepeatedForeignMessage(0).getC());
+ }
+
+ public void testSettingForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = TestAllTypes.newBuilder()
+ // Pass builder for foreign message instance.
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123))
+ .build();
+ TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+ // Create expected version passing foreign message instance explicitly.
+ .setOptionalForeignMessage(
+ ForeignMessage.newBuilder().setC(123).build())
+ .build();
+ // TODO(ngd): Upgrade to using real #equals method once implemented
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = TestAllTypes.newBuilder()
+ // Pass builder for foreign message instance.
+ .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456))
+ .build();
+ TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+ // Create expected version passing foreign message instance explicitly.
+ .addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(456).build())
+ .build();
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testDefaults() throws Exception {
+ TestUtil.assertClear(TestAllTypes.getDefaultInstance());
+ TestUtil.assertClear(TestAllTypes.newBuilder().build());
+
+ assertEquals("\u1234",
+ TestExtremeDefaultValues.getDefaultInstance().getUtf8String());
+ }
+
+ public void testReflectionGetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+ reflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testReflectionSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertAllFieldsSet(message);
+ }
+
+ public void testReflectionRepeatedSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertRepeatedFieldsModified(message);
+ }
+
+ public void testReflectionDefaults() throws Exception {
+ reflectionTester.assertClearViaReflection(
+ TestAllTypes.getDefaultInstance());
+ reflectionTester.assertClearViaReflection(
+ TestAllTypes.newBuilder().build());
+ }
+
+ // =================================================================
+ // Extensions.
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+
+ public void testExtensionAccessors() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertAllExtensionsSet(message);
+ }
+
+ public void testExtensionRepeatedSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestUtil.modifyRepeatedExtensions(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertRepeatedExtensionsModified(message);
+ }
+
+ public void testExtensionDefaults() throws Exception {
+ TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
+ TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
+ }
+
+ public void testExtensionReflectionGetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestAllExtensions message = builder.build();
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testExtensionReflectionSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertAllExtensionsSet(message);
+ }
+
+ public void testExtensionReflectionRepeatedSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ extensionsReflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertRepeatedExtensionsModified(message);
+ }
+
+ public void testExtensionReflectionDefaults() throws Exception {
+ extensionsReflectionTester.assertClearViaReflection(
+ TestAllExtensions.getDefaultInstance());
+ extensionsReflectionTester.assertClearViaReflection(
+ TestAllExtensions.newBuilder().build());
+ }
+
+ public void testClearExtension() throws Exception {
+ // clearExtension() is not actually used in TestUtil, so try it manually.
+ assertFalse(
+ TestAllExtensions.newBuilder()
+ .setExtension(UnittestProto.optionalInt32Extension, 1)
+ .clearExtension(UnittestProto.optionalInt32Extension)
+ .hasExtension(UnittestProto.optionalInt32Extension));
+ assertEquals(0,
+ TestAllExtensions.newBuilder()
+ .addExtension(UnittestProto.repeatedInt32Extension, 1)
+ .clearExtension(UnittestProto.repeatedInt32Extension)
+ .getExtensionCount(UnittestProto.repeatedInt32Extension));
+ }
+
+ // =================================================================
+ // multiple_files_test
+
+ public void testMultipleFilesOption() throws Exception {
+ // We mostly just want to check that things compile.
+ MessageWithNoOuter message =
+ MessageWithNoOuter.newBuilder()
+ .setNested(MessageWithNoOuter.NestedMessage.newBuilder().setI(1))
+ .addForeign(TestAllTypes.newBuilder().setOptionalInt32(1))
+ .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
+ .setForeignEnum(EnumWithNoOuter.BAR)
+ .build();
+ assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
+
+ assertEquals(MultipleFilesTestProto.getDescriptor(),
+ MessageWithNoOuter.getDescriptor().getFile());
+
+ Descriptors.FieldDescriptor field =
+ MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
+ assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(),
+ message.getField(field));
+
+ assertEquals(MultipleFilesTestProto.getDescriptor(),
+ ServiceWithNoOuter.getDescriptor().getFile());
+
+ assertFalse(
+ TestAllExtensions.getDefaultInstance().hasExtension(
+ MultipleFilesTestProto.extensionWithOuter));
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/MessageTest.java b/java/src/test/java/com/google/protobuf/MessageTest.java
new file mode 100644
index 00000000..3dece1ff
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/MessageTest.java
@@ -0,0 +1,299 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+
+import junit.framework.TestCase;
+
+/**
+ * Misc. unit tests for message operations that apply to both generated
+ * and dynamic messages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class MessageTest extends TestCase {
+ // =================================================================
+ // Message-merging tests.
+
+ static final TestAllTypes MERGE_SOURCE =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedString("bar")
+ .build();
+
+ static final TestAllTypes MERGE_DEST =
+ TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+ .addRepeatedString("qux")
+ .build();
+
+ static final String MERGE_RESULT_TEXT =
+ "optional_int32: 1\n" +
+ "optional_int64: 2\n" +
+ "optional_string: \"foo\"\n" +
+ "optional_foreign_message {\n" +
+ " c: 3\n" +
+ "}\n" +
+ "repeated_string: \"qux\"\n" +
+ "repeated_string: \"bar\"\n";
+
+ public void testMergeFrom() throws Exception {
+ TestAllTypes result =
+ TestAllTypes.newBuilder(MERGE_DEST)
+ .mergeFrom(MERGE_SOURCE).build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ /**
+ * Test merging a DynamicMessage into a GeneratedMessage. As long as they
+ * have the same descriptor, this should work, but it is an entirely different
+ * code path.
+ */
+ public void testMergeFromDynamic() throws Exception {
+ TestAllTypes result =
+ TestAllTypes.newBuilder(MERGE_DEST)
+ .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+ .build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ /** Test merging two DynamicMessages. */
+ public void testDynamicMergeFrom() throws Exception {
+ DynamicMessage result =
+ DynamicMessage.newBuilder(MERGE_DEST)
+ .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+ .build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ // =================================================================
+ // Required-field-related tests.
+
+ private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ TestRequired.getDefaultInstance();
+ private static final TestRequired TEST_REQUIRED_INITIALIZED =
+ TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+ public void testRequired() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+
+ assertFalse(builder.isInitialized());
+ builder.setA(1);
+ assertFalse(builder.isInitialized());
+ builder.setB(1);
+ assertFalse(builder.isInitialized());
+ builder.setC(1);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredForeign() throws Exception {
+ TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+
+ assertTrue(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredExtension() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+
+ assertTrue(builder.isInitialized());
+
+ builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredDynamic() throws Exception {
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("a"), 1);
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("b"), 1);
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("c"), 1);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredDynamicForeign() throws Exception {
+ Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
+ DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+ assertTrue(builder.isInitialized());
+
+ builder.setField(descriptor.findFieldByName("optional_message"),
+ TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setField(descriptor.findFieldByName("optional_message"),
+ TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
+ TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
+ TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testUninitializedException() throws Exception {
+ try {
+ TestRequired.newBuilder().build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testBuildPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ TestRequired message = TestRequired.newBuilder().buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testNestedUninitializedException() throws Exception {
+ try {
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals(
+ "Message missing required fields: " +
+ "optional_message.a, " +
+ "optional_message.b, " +
+ "optional_message.c, " +
+ "repeated_message[0].a, " +
+ "repeated_message[0].b, " +
+ "repeated_message[0].c, " +
+ "repeated_message[1].a, " +
+ "repeated_message[1].b, " +
+ "repeated_message[1].c",
+ e.getMessage());
+ }
+ }
+
+ public void testBuildNestedPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ TestRequiredForeign message =
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testParseUnititialized() throws Exception {
+ try {
+ TestRequired.parseFrom(ByteString.EMPTY);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testParseNestedUnititialized() throws Exception {
+ ByteString data =
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .buildPartial().toByteString();
+
+ try {
+ TestRequiredForeign.parseFrom(data);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(
+ "Message missing required fields: " +
+ "optional_message.a, " +
+ "optional_message.b, " +
+ "optional_message.c, " +
+ "repeated_message[0].a, " +
+ "repeated_message[0].b, " +
+ "repeated_message[0].c, " +
+ "repeated_message[1].a, " +
+ "repeated_message[1].b, " +
+ "repeated_message[1].c",
+ e.getMessage());
+ }
+ }
+
+ public void testDynamicUninitializedException() throws Exception {
+ try {
+ DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testDynamicBuildPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ DynamicMessage message =
+ DynamicMessage.newBuilder(TestRequired.getDescriptor())
+ .buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testDynamicParseUnititialized() throws Exception {
+ try {
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java
new file mode 100644
index 00000000..2f83837b
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/ServiceTest.java
@@ -0,0 +1,164 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestService;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.BarRequest;
+import protobuf_unittest.UnittestProto.BarResponse;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.easymock.IArgumentMatcher;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests services and stubs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ServiceTest extends TestCase {
+ private IMocksControl control;
+ private RpcController mockController;
+
+ private final Descriptors.MethodDescriptor fooDescriptor =
+ TestService.getDescriptor().getMethods().get(0);
+ private final Descriptors.MethodDescriptor barDescriptor =
+ TestService.getDescriptor().getMethods().get(1);
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ control = EasyMock.createStrictControl();
+ mockController = control.createMock(RpcController.class);
+ }
+
+ // =================================================================
+
+ /** Tests Service.callMethod(). */
+ public void testCallMethod() throws Exception {
+ FooRequest fooRequest = FooRequest.newBuilder().build();
+ BarRequest barRequest = BarRequest.newBuilder().build();
+ MockCallback<Message> fooCallback = new MockCallback<Message>();
+ MockCallback<Message> barCallback = new MockCallback<Message>();
+ TestService mockService = control.createMock(TestService.class);
+
+ mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
+ this.<FooResponse>wrapsCallback(fooCallback));
+ mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
+ this.<BarResponse>wrapsCallback(barCallback));
+ control.replay();
+
+ mockService.callMethod(fooDescriptor, mockController,
+ fooRequest, fooCallback);
+ mockService.callMethod(barDescriptor, mockController,
+ barRequest, barCallback);
+ control.verify();
+ }
+
+ /** Tests Service.get{Request,Response}Prototype(). */
+ public void testGetPrototype() throws Exception {
+ TestService mockService = control.createMock(TestService.class);
+
+ assertSame(mockService.getRequestPrototype(fooDescriptor),
+ FooRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(fooDescriptor),
+ FooResponse.getDefaultInstance());
+ assertSame(mockService.getRequestPrototype(barDescriptor),
+ BarRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(barDescriptor),
+ BarResponse.getDefaultInstance());
+ }
+
+ /** Tests generated stubs. */
+ public void testStub() throws Exception {
+ FooRequest fooRequest = FooRequest.newBuilder().build();
+ BarRequest barRequest = BarRequest.newBuilder().build();
+ MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
+ MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
+ RpcChannel mockChannel = control.createMock(RpcChannel.class);
+ TestService stub = TestService.newStub(mockChannel);
+
+ mockChannel.callMethod(
+ EasyMock.same(fooDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ EasyMock.same(FooResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(fooCallback));
+ mockChannel.callMethod(
+ EasyMock.same(barDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ EasyMock.same(BarResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(barCallback));
+ control.replay();
+
+ stub.foo(mockController, fooRequest, fooCallback);
+ stub.bar(mockController, barRequest, barCallback);
+ control.verify();
+ }
+
+ // =================================================================
+
+ /**
+ * wrapsCallback() is an EasyMock argument predicate. wrapsCallback(c)
+ * matches a callback if calling that callback causes c to be called.
+ * In other words, c wraps the given callback.
+ */
+ private <Type extends Message> RpcCallback<Type> wrapsCallback(
+ MockCallback callback) {
+ EasyMock.reportMatcher(new WrapsCallback(callback));
+ return null;
+ }
+
+ /** The parameter to wrapsCallback() must be a MockCallback. */
+ private static class MockCallback<Type extends Message>
+ implements RpcCallback<Type> {
+ private boolean called = false;
+
+ public boolean isCalled() { return called; }
+
+ public void reset() { called = false; }
+ public void run(Type message) { called = true; }
+ }
+
+ /** Implementation of the wrapsCallback() argument matcher. */
+ private static class WrapsCallback implements IArgumentMatcher {
+ private MockCallback callback;
+
+ public WrapsCallback(MockCallback callback) {
+ this.callback = callback;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean matches(Object actual) {
+ if (!(actual instanceof RpcCallback)) {
+ return false;
+ }
+ RpcCallback actualCallback = (RpcCallback)actual;
+
+ callback.reset();
+ actualCallback.run(null);
+ return callback.isCalled();
+ }
+
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("wrapsCallback(mockCallback)");
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java
new file mode 100644
index 00000000..af493ad1
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/TestUtil.java
@@ -0,0 +1,2402 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Note: This file contains many lines over 80 characters. It even contains
+// many lines over 100 characters, which fails a presubmit test. However,
+// given the extremely repetitive nature of the file, I (kenton) feel that
+// having similar components of each statement line up is more important than
+// avoiding horizontal scrolling. So, I am bypassing the presubmit check.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Contains methods for setting all fields of {@code TestAllTypes} to
+ * some vaules as well as checking that all the fields are set to those values.
+ * These are useful for testing various protocol message features, e.g.
+ * set all fields of a message, serialize it, parse it, and check that all
+ * fields are set.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+class TestUtil {
+ private TestUtil() {}
+
+ /** Helper to convert a String to ByteString. */
+ private static ByteString toBytes(String str) {
+ try {
+ return ByteString.copyFrom(str.getBytes("UTF-8"));
+ } catch(java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Get a {@code TestAllTypes} with all fields set as they would be by
+ * {@link #setAllFields(TestAllTypes.Builder)}.
+ */
+ public static TestAllTypes getAllSet() {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ setAllFields(builder);
+ return builder.build();
+ }
+
+ /**
+ * Get a {@code TestAllExtensions} with all fields set as they would be by
+ * {@link #setAllExtensions(TestAllExtensions.Builder)}.
+ */
+ public static TestAllExtensions getAllExtensionsSet() {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ setAllExtensions(builder);
+ return builder.build();
+ }
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllFieldsSet()}.
+ */
+ public static void setAllFields(TestAllTypes.Builder message) {
+ message.setOptionalInt32 (101);
+ message.setOptionalInt64 (102);
+ message.setOptionalUint32 (103);
+ message.setOptionalUint64 (104);
+ message.setOptionalSint32 (105);
+ message.setOptionalSint64 (106);
+ message.setOptionalFixed32 (107);
+ message.setOptionalFixed64 (108);
+ message.setOptionalSfixed32(109);
+ message.setOptionalSfixed64(110);
+ message.setOptionalFloat (111);
+ message.setOptionalDouble (112);
+ message.setOptionalBool (true);
+ message.setOptionalString ("115");
+ message.setOptionalBytes (toBytes("116"));
+
+ message.setOptionalGroup(
+ TestAllTypes.OptionalGroup.newBuilder().setA(117).build());
+ message.setOptionalNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+ message.setOptionalForeignMessage(
+ ForeignMessage.newBuilder().setC(119).build());
+ message.setOptionalImportMessage(
+ ImportMessage.newBuilder().setD(120).build());
+
+ message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
+ message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
+ message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
+
+ message.setOptionalStringPiece("124");
+ message.setOptionalCord("125");
+
+ // -----------------------------------------------------------------
+
+ message.addRepeatedInt32 (201);
+ message.addRepeatedInt64 (202);
+ message.addRepeatedUint32 (203);
+ message.addRepeatedUint64 (204);
+ message.addRepeatedSint32 (205);
+ message.addRepeatedSint64 (206);
+ message.addRepeatedFixed32 (207);
+ message.addRepeatedFixed64 (208);
+ message.addRepeatedSfixed32(209);
+ message.addRepeatedSfixed64(210);
+ message.addRepeatedFloat (211);
+ message.addRepeatedDouble (212);
+ message.addRepeatedBool (true);
+ message.addRepeatedString ("215");
+ message.addRepeatedBytes (toBytes("216"));
+
+ message.addRepeatedGroup(
+ TestAllTypes.RepeatedGroup.newBuilder().setA(217).build());
+ message.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ message.addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(219).build());
+ message.addRepeatedImportMessage(
+ ImportMessage.newBuilder().setD(220).build());
+
+ message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
+ message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
+ message.addRepeatedImportEnum (ImportEnum.IMPORT_BAR);
+
+ message.addRepeatedStringPiece("224");
+ message.addRepeatedCord("225");
+
+ // Add a second one of each field.
+ message.addRepeatedInt32 (301);
+ message.addRepeatedInt64 (302);
+ message.addRepeatedUint32 (303);
+ message.addRepeatedUint64 (304);
+ message.addRepeatedSint32 (305);
+ message.addRepeatedSint64 (306);
+ message.addRepeatedFixed32 (307);
+ message.addRepeatedFixed64 (308);
+ message.addRepeatedSfixed32(309);
+ message.addRepeatedSfixed64(310);
+ message.addRepeatedFloat (311);
+ message.addRepeatedDouble (312);
+ message.addRepeatedBool (false);
+ message.addRepeatedString ("315");
+ message.addRepeatedBytes (toBytes("316"));
+
+ message.addRepeatedGroup(
+ TestAllTypes.RepeatedGroup.newBuilder().setA(317).build());
+ message.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+ message.addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(319).build());
+ message.addRepeatedImportMessage(
+ ImportMessage.newBuilder().setD(320).build());
+
+ message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
+ message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
+ message.addRepeatedImportEnum (ImportEnum.IMPORT_BAZ);
+
+ message.addRepeatedStringPiece("324");
+ message.addRepeatedCord("325");
+
+ // -----------------------------------------------------------------
+
+ message.setDefaultInt32 (401);
+ message.setDefaultInt64 (402);
+ message.setDefaultUint32 (403);
+ message.setDefaultUint64 (404);
+ message.setDefaultSint32 (405);
+ message.setDefaultSint64 (406);
+ message.setDefaultFixed32 (407);
+ message.setDefaultFixed64 (408);
+ message.setDefaultSfixed32(409);
+ message.setDefaultSfixed64(410);
+ message.setDefaultFloat (411);
+ message.setDefaultDouble (412);
+ message.setDefaultBool (false);
+ message.setDefaultString ("415");
+ message.setDefaultBytes (toBytes("416"));
+
+ message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
+ message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
+ message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
+
+ message.setDefaultStringPiece("424");
+ message.setDefaultCord("425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated fields of {@code message} to contain the values
+ * expected by {@code assertRepeatedFieldsModified()}.
+ */
+ public static void modifyRepeatedFields(TestAllTypes.Builder message) {
+ message.setRepeatedInt32 (1, 501);
+ message.setRepeatedInt64 (1, 502);
+ message.setRepeatedUint32 (1, 503);
+ message.setRepeatedUint64 (1, 504);
+ message.setRepeatedSint32 (1, 505);
+ message.setRepeatedSint64 (1, 506);
+ message.setRepeatedFixed32 (1, 507);
+ message.setRepeatedFixed64 (1, 508);
+ message.setRepeatedSfixed32(1, 509);
+ message.setRepeatedSfixed64(1, 510);
+ message.setRepeatedFloat (1, 511);
+ message.setRepeatedDouble (1, 512);
+ message.setRepeatedBool (1, true);
+ message.setRepeatedString (1, "515");
+ message.setRepeatedBytes (1, toBytes("516"));
+
+ message.setRepeatedGroup(1,
+ TestAllTypes.RepeatedGroup.newBuilder().setA(517).build());
+ message.setRepeatedNestedMessage(1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+ message.setRepeatedForeignMessage(1,
+ ForeignMessage.newBuilder().setC(519).build());
+ message.setRepeatedImportMessage(1,
+ ImportMessage.newBuilder().setD(520).build());
+
+ message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
+ message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
+ message.setRepeatedImportEnum (1, ImportEnum.IMPORT_FOO);
+
+ message.setRepeatedStringPiece(1, "524");
+ message.setRepeatedCord(1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}.
+ */
+ public static void assertAllFieldsSet(TestAllTypes message) {
+ Assert.assertTrue(message.hasOptionalInt32 ());
+ Assert.assertTrue(message.hasOptionalInt64 ());
+ Assert.assertTrue(message.hasOptionalUint32 ());
+ Assert.assertTrue(message.hasOptionalUint64 ());
+ Assert.assertTrue(message.hasOptionalSint32 ());
+ Assert.assertTrue(message.hasOptionalSint64 ());
+ Assert.assertTrue(message.hasOptionalFixed32 ());
+ Assert.assertTrue(message.hasOptionalFixed64 ());
+ Assert.assertTrue(message.hasOptionalSfixed32());
+ Assert.assertTrue(message.hasOptionalSfixed64());
+ Assert.assertTrue(message.hasOptionalFloat ());
+ Assert.assertTrue(message.hasOptionalDouble ());
+ Assert.assertTrue(message.hasOptionalBool ());
+ Assert.assertTrue(message.hasOptionalString ());
+ Assert.assertTrue(message.hasOptionalBytes ());
+
+ Assert.assertTrue(message.hasOptionalGroup ());
+ Assert.assertTrue(message.hasOptionalNestedMessage ());
+ Assert.assertTrue(message.hasOptionalForeignMessage());
+ Assert.assertTrue(message.hasOptionalImportMessage ());
+
+ Assert.assertTrue(message.getOptionalGroup ().hasA());
+ Assert.assertTrue(message.getOptionalNestedMessage ().hasBb());
+ Assert.assertTrue(message.getOptionalForeignMessage().hasC());
+ Assert.assertTrue(message.getOptionalImportMessage ().hasD());
+
+ Assert.assertTrue(message.hasOptionalNestedEnum ());
+ Assert.assertTrue(message.hasOptionalForeignEnum());
+ Assert.assertTrue(message.hasOptionalImportEnum ());
+
+ Assert.assertTrue(message.hasOptionalStringPiece());
+ Assert.assertTrue(message.hasOptionalCord());
+
+ Assert.assertEquals(101 , message.getOptionalInt32 ());
+ Assert.assertEquals(102 , message.getOptionalInt64 ());
+ Assert.assertEquals(103 , message.getOptionalUint32 ());
+ Assert.assertEquals(104 , message.getOptionalUint64 ());
+ Assert.assertEquals(105 , message.getOptionalSint32 ());
+ Assert.assertEquals(106 , message.getOptionalSint64 ());
+ Assert.assertEquals(107 , message.getOptionalFixed32 ());
+ Assert.assertEquals(108 , message.getOptionalFixed64 ());
+ Assert.assertEquals(109 , message.getOptionalSfixed32());
+ Assert.assertEquals(110 , message.getOptionalSfixed64());
+ Assert.assertEquals(111 , message.getOptionalFloat (), 0.0);
+ Assert.assertEquals(112 , message.getOptionalDouble (), 0.0);
+ Assert.assertEquals(true , message.getOptionalBool ());
+ Assert.assertEquals("115", message.getOptionalString ());
+ Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
+
+ Assert.assertEquals(117, message.getOptionalGroup ().getA());
+ Assert.assertEquals(118, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(119, message.getOptionalForeignMessage().getC());
+ Assert.assertEquals(120, message.getOptionalImportMessage ().getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
+
+ Assert.assertEquals("124", message.getOptionalStringPiece());
+ Assert.assertEquals("125", message.getOptionalCord());
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getRepeatedInt32Count ());
+ Assert.assertEquals(2, message.getRepeatedInt64Count ());
+ Assert.assertEquals(2, message.getRepeatedUint32Count ());
+ Assert.assertEquals(2, message.getRepeatedUint64Count ());
+ Assert.assertEquals(2, message.getRepeatedSint32Count ());
+ Assert.assertEquals(2, message.getRepeatedSint64Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(2, message.getRepeatedFloatCount ());
+ Assert.assertEquals(2, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(2, message.getRepeatedBoolCount ());
+ Assert.assertEquals(2, message.getRepeatedStringCount ());
+ Assert.assertEquals(2, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(2, message.getRepeatedGroupCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(2, message.getRepeatedCordCount());
+
+ Assert.assertEquals(201 , message.getRepeatedInt32 (0));
+ Assert.assertEquals(202 , message.getRepeatedInt64 (0));
+ Assert.assertEquals(203 , message.getRepeatedUint32 (0));
+ Assert.assertEquals(204 , message.getRepeatedUint64 (0));
+ Assert.assertEquals(205 , message.getRepeatedSint32 (0));
+ Assert.assertEquals(206 , message.getRepeatedSint64 (0));
+ Assert.assertEquals(207 , message.getRepeatedFixed32 (0));
+ Assert.assertEquals(208 , message.getRepeatedFixed64 (0));
+ Assert.assertEquals(209 , message.getRepeatedSfixed32(0));
+ Assert.assertEquals(210 , message.getRepeatedSfixed64(0));
+ Assert.assertEquals(211 , message.getRepeatedFloat (0), 0.0);
+ Assert.assertEquals(212 , message.getRepeatedDouble (0), 0.0);
+ Assert.assertEquals(true , message.getRepeatedBool (0));
+ Assert.assertEquals("215", message.getRepeatedString (0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+ Assert.assertEquals(217, message.getRepeatedGroup (0).getA());
+ Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+ Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+ Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+ Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+ Assert.assertEquals("225", message.getRepeatedCord(0));
+
+ Assert.assertEquals(301 , message.getRepeatedInt32 (1));
+ Assert.assertEquals(302 , message.getRepeatedInt64 (1));
+ Assert.assertEquals(303 , message.getRepeatedUint32 (1));
+ Assert.assertEquals(304 , message.getRepeatedUint64 (1));
+ Assert.assertEquals(305 , message.getRepeatedSint32 (1));
+ Assert.assertEquals(306 , message.getRepeatedSint64 (1));
+ Assert.assertEquals(307 , message.getRepeatedFixed32 (1));
+ Assert.assertEquals(308 , message.getRepeatedFixed64 (1));
+ Assert.assertEquals(309 , message.getRepeatedSfixed32(1));
+ Assert.assertEquals(310 , message.getRepeatedSfixed64(1));
+ Assert.assertEquals(311 , message.getRepeatedFloat (1), 0.0);
+ Assert.assertEquals(312 , message.getRepeatedDouble (1), 0.0);
+ Assert.assertEquals(false, message.getRepeatedBool (1));
+ Assert.assertEquals("315", message.getRepeatedString (1));
+ Assert.assertEquals(toBytes("316"), message.getRepeatedBytes(1));
+
+ Assert.assertEquals(317, message.getRepeatedGroup (1).getA());
+ Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
+ Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
+ Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
+ Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnum(1));
+
+ Assert.assertEquals("324", message.getRepeatedStringPiece(1));
+ Assert.assertEquals("325", message.getRepeatedCord(1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasDefaultInt32 ());
+ Assert.assertTrue(message.hasDefaultInt64 ());
+ Assert.assertTrue(message.hasDefaultUint32 ());
+ Assert.assertTrue(message.hasDefaultUint64 ());
+ Assert.assertTrue(message.hasDefaultSint32 ());
+ Assert.assertTrue(message.hasDefaultSint64 ());
+ Assert.assertTrue(message.hasDefaultFixed32 ());
+ Assert.assertTrue(message.hasDefaultFixed64 ());
+ Assert.assertTrue(message.hasDefaultSfixed32());
+ Assert.assertTrue(message.hasDefaultSfixed64());
+ Assert.assertTrue(message.hasDefaultFloat ());
+ Assert.assertTrue(message.hasDefaultDouble ());
+ Assert.assertTrue(message.hasDefaultBool ());
+ Assert.assertTrue(message.hasDefaultString ());
+ Assert.assertTrue(message.hasDefaultBytes ());
+
+ Assert.assertTrue(message.hasDefaultNestedEnum ());
+ Assert.assertTrue(message.hasDefaultForeignEnum());
+ Assert.assertTrue(message.hasDefaultImportEnum ());
+
+ Assert.assertTrue(message.hasDefaultStringPiece());
+ Assert.assertTrue(message.hasDefaultCord());
+
+ Assert.assertEquals(401 , message.getDefaultInt32 ());
+ Assert.assertEquals(402 , message.getDefaultInt64 ());
+ Assert.assertEquals(403 , message.getDefaultUint32 ());
+ Assert.assertEquals(404 , message.getDefaultUint64 ());
+ Assert.assertEquals(405 , message.getDefaultSint32 ());
+ Assert.assertEquals(406 , message.getDefaultSint64 ());
+ Assert.assertEquals(407 , message.getDefaultFixed32 ());
+ Assert.assertEquals(408 , message.getDefaultFixed64 ());
+ Assert.assertEquals(409 , message.getDefaultSfixed32());
+ Assert.assertEquals(410 , message.getDefaultSfixed64());
+ Assert.assertEquals(411 , message.getDefaultFloat (), 0.0);
+ Assert.assertEquals(412 , message.getDefaultDouble (), 0.0);
+ Assert.assertEquals(false, message.getDefaultBool ());
+ Assert.assertEquals("415", message.getDefaultString ());
+ Assert.assertEquals(toBytes("416"), message.getDefaultBytes());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
+
+ Assert.assertEquals("424", message.getDefaultStringPiece());
+ Assert.assertEquals("425", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are cleared, and that getting the fields returns their
+ * default values.
+ */
+ public static void assertClear(TestAllTypes message) {
+ // hasBlah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasOptionalInt32 ());
+ Assert.assertFalse(message.hasOptionalInt64 ());
+ Assert.assertFalse(message.hasOptionalUint32 ());
+ Assert.assertFalse(message.hasOptionalUint64 ());
+ Assert.assertFalse(message.hasOptionalSint32 ());
+ Assert.assertFalse(message.hasOptionalSint64 ());
+ Assert.assertFalse(message.hasOptionalFixed32 ());
+ Assert.assertFalse(message.hasOptionalFixed64 ());
+ Assert.assertFalse(message.hasOptionalSfixed32());
+ Assert.assertFalse(message.hasOptionalSfixed64());
+ Assert.assertFalse(message.hasOptionalFloat ());
+ Assert.assertFalse(message.hasOptionalDouble ());
+ Assert.assertFalse(message.hasOptionalBool ());
+ Assert.assertFalse(message.hasOptionalString ());
+ Assert.assertFalse(message.hasOptionalBytes ());
+
+ Assert.assertFalse(message.hasOptionalGroup ());
+ Assert.assertFalse(message.hasOptionalNestedMessage ());
+ Assert.assertFalse(message.hasOptionalForeignMessage());
+ Assert.assertFalse(message.hasOptionalImportMessage ());
+
+ Assert.assertFalse(message.hasOptionalNestedEnum ());
+ Assert.assertFalse(message.hasOptionalForeignEnum());
+ Assert.assertFalse(message.hasOptionalImportEnum ());
+
+ Assert.assertFalse(message.hasOptionalStringPiece());
+ Assert.assertFalse(message.hasOptionalCord());
+
+ // Optional fields without defaults are set to zero or something like it.
+ Assert.assertEquals(0 , message.getOptionalInt32 ());
+ Assert.assertEquals(0 , message.getOptionalInt64 ());
+ Assert.assertEquals(0 , message.getOptionalUint32 ());
+ Assert.assertEquals(0 , message.getOptionalUint64 ());
+ Assert.assertEquals(0 , message.getOptionalSint32 ());
+ Assert.assertEquals(0 , message.getOptionalSint64 ());
+ Assert.assertEquals(0 , message.getOptionalFixed32 ());
+ Assert.assertEquals(0 , message.getOptionalFixed64 ());
+ Assert.assertEquals(0 , message.getOptionalSfixed32());
+ Assert.assertEquals(0 , message.getOptionalSfixed64());
+ Assert.assertEquals(0 , message.getOptionalFloat (), 0.0);
+ Assert.assertEquals(0 , message.getOptionalDouble (), 0.0);
+ Assert.assertEquals(false, message.getOptionalBool ());
+ Assert.assertEquals("" , message.getOptionalString ());
+ Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(message.getOptionalGroup ().hasA());
+ Assert.assertFalse(message.getOptionalNestedMessage ().hasBb());
+ Assert.assertFalse(message.getOptionalForeignMessage().hasC());
+ Assert.assertFalse(message.getOptionalImportMessage ().hasD());
+
+ Assert.assertEquals(0, message.getOptionalGroup ().getA());
+ Assert.assertEquals(0, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(0, message.getOptionalForeignMessage().getC());
+ Assert.assertEquals(0, message.getOptionalImportMessage ().getD());
+
+ // Enums without defaults are set to the first value in the enum.
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getOptionalForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getOptionalImportEnum());
+
+ Assert.assertEquals("", message.getOptionalStringPiece());
+ Assert.assertEquals("", message.getOptionalCord());
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getRepeatedInt32Count ());
+ Assert.assertEquals(0, message.getRepeatedInt64Count ());
+ Assert.assertEquals(0, message.getRepeatedUint32Count ());
+ Assert.assertEquals(0, message.getRepeatedUint64Count ());
+ Assert.assertEquals(0, message.getRepeatedSint32Count ());
+ Assert.assertEquals(0, message.getRepeatedSint64Count ());
+ Assert.assertEquals(0, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(0, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(0, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(0, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(0, message.getRepeatedFloatCount ());
+ Assert.assertEquals(0, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(0, message.getRepeatedBoolCount ());
+ Assert.assertEquals(0, message.getRepeatedStringCount ());
+ Assert.assertEquals(0, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(0, message.getRepeatedGroupCount ());
+ Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(0, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(0, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(0, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(0, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(0, message.getRepeatedCordCount());
+
+ // hasBlah() should also be false for all default fields.
+ Assert.assertFalse(message.hasDefaultInt32 ());
+ Assert.assertFalse(message.hasDefaultInt64 ());
+ Assert.assertFalse(message.hasDefaultUint32 ());
+ Assert.assertFalse(message.hasDefaultUint64 ());
+ Assert.assertFalse(message.hasDefaultSint32 ());
+ Assert.assertFalse(message.hasDefaultSint64 ());
+ Assert.assertFalse(message.hasDefaultFixed32 ());
+ Assert.assertFalse(message.hasDefaultFixed64 ());
+ Assert.assertFalse(message.hasDefaultSfixed32());
+ Assert.assertFalse(message.hasDefaultSfixed64());
+ Assert.assertFalse(message.hasDefaultFloat ());
+ Assert.assertFalse(message.hasDefaultDouble ());
+ Assert.assertFalse(message.hasDefaultBool ());
+ Assert.assertFalse(message.hasDefaultString ());
+ Assert.assertFalse(message.hasDefaultBytes ());
+
+ Assert.assertFalse(message.hasDefaultNestedEnum ());
+ Assert.assertFalse(message.hasDefaultForeignEnum());
+ Assert.assertFalse(message.hasDefaultImportEnum ());
+
+ Assert.assertFalse(message.hasDefaultStringPiece());
+ Assert.assertFalse(message.hasDefaultCord());
+
+ // Fields with defaults have their default values (duh).
+ Assert.assertEquals( 41 , message.getDefaultInt32 ());
+ Assert.assertEquals( 42 , message.getDefaultInt64 ());
+ Assert.assertEquals( 43 , message.getDefaultUint32 ());
+ Assert.assertEquals( 44 , message.getDefaultUint64 ());
+ Assert.assertEquals(-45 , message.getDefaultSint32 ());
+ Assert.assertEquals( 46 , message.getDefaultSint64 ());
+ Assert.assertEquals( 47 , message.getDefaultFixed32 ());
+ Assert.assertEquals( 48 , message.getDefaultFixed64 ());
+ Assert.assertEquals( 49 , message.getDefaultSfixed32());
+ Assert.assertEquals(-50 , message.getDefaultSfixed64());
+ Assert.assertEquals( 51.5 , message.getDefaultFloat (), 0.0);
+ Assert.assertEquals( 52e3 , message.getDefaultDouble (), 0.0);
+ Assert.assertEquals(true , message.getDefaultBool ());
+ Assert.assertEquals("hello", message.getDefaultString ());
+ Assert.assertEquals(toBytes("world"), message.getDefaultBytes());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
+
+ Assert.assertEquals("abc", message.getDefaultStringPiece());
+ Assert.assertEquals("123", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}
+ * followed by {@code modifyRepeatedFields}.
+ */
+ public static void assertRepeatedFieldsModified(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.assertEquals(2, message.getRepeatedInt32Count ());
+ Assert.assertEquals(2, message.getRepeatedInt64Count ());
+ Assert.assertEquals(2, message.getRepeatedUint32Count ());
+ Assert.assertEquals(2, message.getRepeatedUint64Count ());
+ Assert.assertEquals(2, message.getRepeatedSint32Count ());
+ Assert.assertEquals(2, message.getRepeatedSint64Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(2, message.getRepeatedFloatCount ());
+ Assert.assertEquals(2, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(2, message.getRepeatedBoolCount ());
+ Assert.assertEquals(2, message.getRepeatedStringCount ());
+ Assert.assertEquals(2, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(2, message.getRepeatedGroupCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(2, message.getRepeatedCordCount());
+
+ Assert.assertEquals(201 , message.getRepeatedInt32 (0));
+ Assert.assertEquals(202L , message.getRepeatedInt64 (0));
+ Assert.assertEquals(203 , message.getRepeatedUint32 (0));
+ Assert.assertEquals(204L , message.getRepeatedUint64 (0));
+ Assert.assertEquals(205 , message.getRepeatedSint32 (0));
+ Assert.assertEquals(206L , message.getRepeatedSint64 (0));
+ Assert.assertEquals(207 , message.getRepeatedFixed32 (0));
+ Assert.assertEquals(208L , message.getRepeatedFixed64 (0));
+ Assert.assertEquals(209 , message.getRepeatedSfixed32(0));
+ Assert.assertEquals(210L , message.getRepeatedSfixed64(0));
+ Assert.assertEquals(211F , message.getRepeatedFloat (0));
+ Assert.assertEquals(212D , message.getRepeatedDouble (0));
+ Assert.assertEquals(true , message.getRepeatedBool (0));
+ Assert.assertEquals("215", message.getRepeatedString (0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+ Assert.assertEquals(217, message.getRepeatedGroup (0).getA());
+ Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+ Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+ Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+ Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+ Assert.assertEquals("225", message.getRepeatedCord(0));
+
+ // Actually verify the second (modified) elements now.
+ Assert.assertEquals(501 , message.getRepeatedInt32 (1));
+ Assert.assertEquals(502L , message.getRepeatedInt64 (1));
+ Assert.assertEquals(503 , message.getRepeatedUint32 (1));
+ Assert.assertEquals(504L , message.getRepeatedUint64 (1));
+ Assert.assertEquals(505 , message.getRepeatedSint32 (1));
+ Assert.assertEquals(506L , message.getRepeatedSint64 (1));
+ Assert.assertEquals(507 , message.getRepeatedFixed32 (1));
+ Assert.assertEquals(508L , message.getRepeatedFixed64 (1));
+ Assert.assertEquals(509 , message.getRepeatedSfixed32(1));
+ Assert.assertEquals(510L , message.getRepeatedSfixed64(1));
+ Assert.assertEquals(511F , message.getRepeatedFloat (1));
+ Assert.assertEquals(512D , message.getRepeatedDouble (1));
+ Assert.assertEquals(true , message.getRepeatedBool (1));
+ Assert.assertEquals("515", message.getRepeatedString (1));
+ Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
+
+ Assert.assertEquals(517, message.getRepeatedGroup (1).getA());
+ Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
+ Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
+ Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnum(1));
+
+ Assert.assertEquals("524", message.getRepeatedStringPiece(1));
+ Assert.assertEquals("525", message.getRepeatedCord(1));
+ }
+
+ // ===================================================================
+ // Like above, but for extensions
+
+ // Java gets confused with things like assertEquals(int, Integer): it can't
+ // decide whether to call assertEquals(int, int) or assertEquals(Object,
+ // Object). So we define these methods to help it.
+ private static void assertEqualsExactType(int a, int b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(long a, long b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(float a, float b) {
+ Assert.assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(double a, double b) {
+ Assert.assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(boolean a, boolean b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(String a, String b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ByteString a, ByteString b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
+ TestAllTypes.NestedEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
+ Assert.assertEquals(a, b);
+ }
+
+ /**
+ * Get an unmodifiable {@link ExtensionRegistry} containing all the
+ * extensions of {@code TestAllExtensions}.
+ */
+ public static ExtensionRegistry getExtensionRegistry() {
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ registerAllExtensions(registry);
+ return registry.getUnmodifiable();
+ }
+
+ /**
+ * Register all of {@code TestAllExtensions}' extensions with the
+ * given {@link ExtensionRegistry}.
+ */
+ public static void registerAllExtensions(ExtensionRegistry registry) {
+ registry.add(UnittestProto.optionalInt32Extension );
+ registry.add(UnittestProto.optionalInt64Extension );
+ registry.add(UnittestProto.optionalUint32Extension );
+ registry.add(UnittestProto.optionalUint64Extension );
+ registry.add(UnittestProto.optionalSint32Extension );
+ registry.add(UnittestProto.optionalSint64Extension );
+ registry.add(UnittestProto.optionalFixed32Extension );
+ registry.add(UnittestProto.optionalFixed64Extension );
+ registry.add(UnittestProto.optionalSfixed32Extension );
+ registry.add(UnittestProto.optionalSfixed64Extension );
+ registry.add(UnittestProto.optionalFloatExtension );
+ registry.add(UnittestProto.optionalDoubleExtension );
+ registry.add(UnittestProto.optionalBoolExtension );
+ registry.add(UnittestProto.optionalStringExtension );
+ registry.add(UnittestProto.optionalBytesExtension );
+ registry.add(UnittestProto.optionalGroupExtension );
+ registry.add(UnittestProto.optionalNestedMessageExtension );
+ registry.add(UnittestProto.optionalForeignMessageExtension);
+ registry.add(UnittestProto.optionalImportMessageExtension );
+ registry.add(UnittestProto.optionalNestedEnumExtension );
+ registry.add(UnittestProto.optionalForeignEnumExtension );
+ registry.add(UnittestProto.optionalImportEnumExtension );
+ registry.add(UnittestProto.optionalStringPieceExtension );
+ registry.add(UnittestProto.optionalCordExtension );
+
+ registry.add(UnittestProto.repeatedInt32Extension );
+ registry.add(UnittestProto.repeatedInt64Extension );
+ registry.add(UnittestProto.repeatedUint32Extension );
+ registry.add(UnittestProto.repeatedUint64Extension );
+ registry.add(UnittestProto.repeatedSint32Extension );
+ registry.add(UnittestProto.repeatedSint64Extension );
+ registry.add(UnittestProto.repeatedFixed32Extension );
+ registry.add(UnittestProto.repeatedFixed64Extension );
+ registry.add(UnittestProto.repeatedSfixed32Extension );
+ registry.add(UnittestProto.repeatedSfixed64Extension );
+ registry.add(UnittestProto.repeatedFloatExtension );
+ registry.add(UnittestProto.repeatedDoubleExtension );
+ registry.add(UnittestProto.repeatedBoolExtension );
+ registry.add(UnittestProto.repeatedStringExtension );
+ registry.add(UnittestProto.repeatedBytesExtension );
+ registry.add(UnittestProto.repeatedGroupExtension );
+ registry.add(UnittestProto.repeatedNestedMessageExtension );
+ registry.add(UnittestProto.repeatedForeignMessageExtension);
+ registry.add(UnittestProto.repeatedImportMessageExtension );
+ registry.add(UnittestProto.repeatedNestedEnumExtension );
+ registry.add(UnittestProto.repeatedForeignEnumExtension );
+ registry.add(UnittestProto.repeatedImportEnumExtension );
+ registry.add(UnittestProto.repeatedStringPieceExtension );
+ registry.add(UnittestProto.repeatedCordExtension );
+
+ registry.add(UnittestProto.defaultInt32Extension );
+ registry.add(UnittestProto.defaultInt64Extension );
+ registry.add(UnittestProto.defaultUint32Extension );
+ registry.add(UnittestProto.defaultUint64Extension );
+ registry.add(UnittestProto.defaultSint32Extension );
+ registry.add(UnittestProto.defaultSint64Extension );
+ registry.add(UnittestProto.defaultFixed32Extension );
+ registry.add(UnittestProto.defaultFixed64Extension );
+ registry.add(UnittestProto.defaultSfixed32Extension );
+ registry.add(UnittestProto.defaultSfixed64Extension );
+ registry.add(UnittestProto.defaultFloatExtension );
+ registry.add(UnittestProto.defaultDoubleExtension );
+ registry.add(UnittestProto.defaultBoolExtension );
+ registry.add(UnittestProto.defaultStringExtension );
+ registry.add(UnittestProto.defaultBytesExtension );
+ registry.add(UnittestProto.defaultNestedEnumExtension );
+ registry.add(UnittestProto.defaultForeignEnumExtension);
+ registry.add(UnittestProto.defaultImportEnumExtension );
+ registry.add(UnittestProto.defaultStringPieceExtension);
+ registry.add(UnittestProto.defaultCordExtension );
+ }
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllExtensionsSet()}.
+ */
+ public static void setAllExtensions(TestAllExtensions.Builder message) {
+ message.setExtension(UnittestProto.optionalInt32Extension , 101);
+ message.setExtension(UnittestProto.optionalInt64Extension , 102L);
+ message.setExtension(UnittestProto.optionalUint32Extension , 103);
+ message.setExtension(UnittestProto.optionalUint64Extension , 104L);
+ message.setExtension(UnittestProto.optionalSint32Extension , 105);
+ message.setExtension(UnittestProto.optionalSint64Extension , 106L);
+ message.setExtension(UnittestProto.optionalFixed32Extension , 107);
+ message.setExtension(UnittestProto.optionalFixed64Extension , 108L);
+ message.setExtension(UnittestProto.optionalSfixed32Extension, 109);
+ message.setExtension(UnittestProto.optionalSfixed64Extension, 110L);
+ message.setExtension(UnittestProto.optionalFloatExtension , 111F);
+ message.setExtension(UnittestProto.optionalDoubleExtension , 112D);
+ message.setExtension(UnittestProto.optionalBoolExtension , true);
+ message.setExtension(UnittestProto.optionalStringExtension , "115");
+ message.setExtension(UnittestProto.optionalBytesExtension , toBytes("116"));
+
+ message.setExtension(UnittestProto.optionalGroupExtension,
+ UnittestProto.OptionalGroup_extension.newBuilder().setA(117).build());
+ message.setExtension(UnittestProto.optionalNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+ message.setExtension(UnittestProto.optionalForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(119).build());
+ message.setExtension(UnittestProto.optionalImportMessageExtension,
+ ImportMessage.newBuilder().setD(120).build());
+
+ message.setExtension(UnittestProto.optionalNestedEnumExtension,
+ TestAllTypes.NestedEnum.BAZ);
+ message.setExtension(UnittestProto.optionalForeignEnumExtension,
+ ForeignEnum.FOREIGN_BAZ);
+ message.setExtension(UnittestProto.optionalImportEnumExtension,
+ ImportEnum.IMPORT_BAZ);
+
+ message.setExtension(UnittestProto.optionalStringPieceExtension, "124");
+ message.setExtension(UnittestProto.optionalCordExtension, "125");
+
+ // -----------------------------------------------------------------
+
+ message.addExtension(UnittestProto.repeatedInt32Extension , 201);
+ message.addExtension(UnittestProto.repeatedInt64Extension , 202L);
+ message.addExtension(UnittestProto.repeatedUint32Extension , 203);
+ message.addExtension(UnittestProto.repeatedUint64Extension , 204L);
+ message.addExtension(UnittestProto.repeatedSint32Extension , 205);
+ message.addExtension(UnittestProto.repeatedSint64Extension , 206L);
+ message.addExtension(UnittestProto.repeatedFixed32Extension , 207);
+ message.addExtension(UnittestProto.repeatedFixed64Extension , 208L);
+ message.addExtension(UnittestProto.repeatedSfixed32Extension, 209);
+ message.addExtension(UnittestProto.repeatedSfixed64Extension, 210L);
+ message.addExtension(UnittestProto.repeatedFloatExtension , 211F);
+ message.addExtension(UnittestProto.repeatedDoubleExtension , 212D);
+ message.addExtension(UnittestProto.repeatedBoolExtension , true);
+ message.addExtension(UnittestProto.repeatedStringExtension , "215");
+ message.addExtension(UnittestProto.repeatedBytesExtension , toBytes("216"));
+
+ message.addExtension(UnittestProto.repeatedGroupExtension,
+ UnittestProto.RepeatedGroup_extension.newBuilder().setA(217).build());
+ message.addExtension(UnittestProto.repeatedNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ message.addExtension(UnittestProto.repeatedForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(219).build());
+ message.addExtension(UnittestProto.repeatedImportMessageExtension,
+ ImportMessage.newBuilder().setD(220).build());
+
+ message.addExtension(UnittestProto.repeatedNestedEnumExtension,
+ TestAllTypes.NestedEnum.BAR);
+ message.addExtension(UnittestProto.repeatedForeignEnumExtension,
+ ForeignEnum.FOREIGN_BAR);
+ message.addExtension(UnittestProto.repeatedImportEnumExtension,
+ ImportEnum.IMPORT_BAR);
+
+ message.addExtension(UnittestProto.repeatedStringPieceExtension, "224");
+ message.addExtension(UnittestProto.repeatedCordExtension, "225");
+
+ // Add a second one of each field.
+ message.addExtension(UnittestProto.repeatedInt32Extension , 301);
+ message.addExtension(UnittestProto.repeatedInt64Extension , 302L);
+ message.addExtension(UnittestProto.repeatedUint32Extension , 303);
+ message.addExtension(UnittestProto.repeatedUint64Extension , 304L);
+ message.addExtension(UnittestProto.repeatedSint32Extension , 305);
+ message.addExtension(UnittestProto.repeatedSint64Extension , 306L);
+ message.addExtension(UnittestProto.repeatedFixed32Extension , 307);
+ message.addExtension(UnittestProto.repeatedFixed64Extension , 308L);
+ message.addExtension(UnittestProto.repeatedSfixed32Extension, 309);
+ message.addExtension(UnittestProto.repeatedSfixed64Extension, 310L);
+ message.addExtension(UnittestProto.repeatedFloatExtension , 311F);
+ message.addExtension(UnittestProto.repeatedDoubleExtension , 312D);
+ message.addExtension(UnittestProto.repeatedBoolExtension , false);
+ message.addExtension(UnittestProto.repeatedStringExtension , "315");
+ message.addExtension(UnittestProto.repeatedBytesExtension , toBytes("316"));
+
+ message.addExtension(UnittestProto.repeatedGroupExtension,
+ UnittestProto.RepeatedGroup_extension.newBuilder().setA(317).build());
+ message.addExtension(UnittestProto.repeatedNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+ message.addExtension(UnittestProto.repeatedForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(319).build());
+ message.addExtension(UnittestProto.repeatedImportMessageExtension,
+ ImportMessage.newBuilder().setD(320).build());
+
+ message.addExtension(UnittestProto.repeatedNestedEnumExtension,
+ TestAllTypes.NestedEnum.BAZ);
+ message.addExtension(UnittestProto.repeatedForeignEnumExtension,
+ ForeignEnum.FOREIGN_BAZ);
+ message.addExtension(UnittestProto.repeatedImportEnumExtension,
+ ImportEnum.IMPORT_BAZ);
+
+ message.addExtension(UnittestProto.repeatedStringPieceExtension, "324");
+ message.addExtension(UnittestProto.repeatedCordExtension, "325");
+
+ // -----------------------------------------------------------------
+
+ message.setExtension(UnittestProto.defaultInt32Extension , 401);
+ message.setExtension(UnittestProto.defaultInt64Extension , 402L);
+ message.setExtension(UnittestProto.defaultUint32Extension , 403);
+ message.setExtension(UnittestProto.defaultUint64Extension , 404L);
+ message.setExtension(UnittestProto.defaultSint32Extension , 405);
+ message.setExtension(UnittestProto.defaultSint64Extension , 406L);
+ message.setExtension(UnittestProto.defaultFixed32Extension , 407);
+ message.setExtension(UnittestProto.defaultFixed64Extension , 408L);
+ message.setExtension(UnittestProto.defaultSfixed32Extension, 409);
+ message.setExtension(UnittestProto.defaultSfixed64Extension, 410L);
+ message.setExtension(UnittestProto.defaultFloatExtension , 411F);
+ message.setExtension(UnittestProto.defaultDoubleExtension , 412D);
+ message.setExtension(UnittestProto.defaultBoolExtension , false);
+ message.setExtension(UnittestProto.defaultStringExtension , "415");
+ message.setExtension(UnittestProto.defaultBytesExtension , toBytes("416"));
+
+ message.setExtension(UnittestProto.defaultNestedEnumExtension,
+ TestAllTypes.NestedEnum.FOO);
+ message.setExtension(UnittestProto.defaultForeignEnumExtension,
+ ForeignEnum.FOREIGN_FOO);
+ message.setExtension(UnittestProto.defaultImportEnumExtension,
+ ImportEnum.IMPORT_FOO);
+
+ message.setExtension(UnittestProto.defaultStringPieceExtension, "424");
+ message.setExtension(UnittestProto.defaultCordExtension, "425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated extensions of {@code message} to contain the values
+ * expected by {@code assertRepeatedExtensionsModified()}.
+ */
+ public static void modifyRepeatedExtensions(
+ TestAllExtensions.Builder message) {
+ message.setExtension(UnittestProto.repeatedInt32Extension , 1, 501);
+ message.setExtension(UnittestProto.repeatedInt64Extension , 1, 502L);
+ message.setExtension(UnittestProto.repeatedUint32Extension , 1, 503);
+ message.setExtension(UnittestProto.repeatedUint64Extension , 1, 504L);
+ message.setExtension(UnittestProto.repeatedSint32Extension , 1, 505);
+ message.setExtension(UnittestProto.repeatedSint64Extension , 1, 506L);
+ message.setExtension(UnittestProto.repeatedFixed32Extension , 1, 507);
+ message.setExtension(UnittestProto.repeatedFixed64Extension , 1, 508L);
+ message.setExtension(UnittestProto.repeatedSfixed32Extension, 1, 509);
+ message.setExtension(UnittestProto.repeatedSfixed64Extension, 1, 510L);
+ message.setExtension(UnittestProto.repeatedFloatExtension , 1, 511F);
+ message.setExtension(UnittestProto.repeatedDoubleExtension , 1, 512D);
+ message.setExtension(UnittestProto.repeatedBoolExtension , 1, true);
+ message.setExtension(UnittestProto.repeatedStringExtension , 1, "515");
+ message.setExtension(UnittestProto.repeatedBytesExtension , 1, toBytes("516"));
+
+ message.setExtension(UnittestProto.repeatedGroupExtension, 1,
+ UnittestProto.RepeatedGroup_extension.newBuilder().setA(517).build());
+ message.setExtension(UnittestProto.repeatedNestedMessageExtension, 1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+ message.setExtension(UnittestProto.repeatedForeignMessageExtension, 1,
+ ForeignMessage.newBuilder().setC(519).build());
+ message.setExtension(UnittestProto.repeatedImportMessageExtension, 1,
+ ImportMessage.newBuilder().setD(520).build());
+
+ message.setExtension(UnittestProto.repeatedNestedEnumExtension , 1,
+ TestAllTypes.NestedEnum.FOO);
+ message.setExtension(UnittestProto.repeatedForeignEnumExtension, 1,
+ ForeignEnum.FOREIGN_FOO);
+ message.setExtension(UnittestProto.repeatedImportEnumExtension , 1,
+ ImportEnum.IMPORT_FOO);
+
+ message.setExtension(UnittestProto.repeatedStringPieceExtension, 1, "524");
+ message.setExtension(UnittestProto.repeatedCordExtension, 1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}.
+ */
+ public static void assertAllExtensionsSet(TestAllExtensions message) {
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalInt32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalInt64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalUint32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalUint64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalSint32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalSint64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalFixed32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalFixed64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalSfixed32Extension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalSfixed64Extension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalFloatExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalDoubleExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalBoolExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalStringExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalBytesExtension ));
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalGroupExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalNestedMessageExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalForeignMessageExtension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalImportMessageExtension ));
+
+ Assert.assertTrue(message.getExtension(UnittestProto.optionalGroupExtension ).hasA());
+ Assert.assertTrue(message.getExtension(UnittestProto.optionalNestedMessageExtension ).hasBb());
+ Assert.assertTrue(message.getExtension(UnittestProto.optionalForeignMessageExtension).hasC());
+ Assert.assertTrue(message.getExtension(UnittestProto.optionalImportMessageExtension ).hasD());
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalNestedEnumExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalForeignEnumExtension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalImportEnumExtension ));
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalStringPieceExtension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.optionalCordExtension));
+
+ assertEqualsExactType(101 , message.getExtension(UnittestProto.optionalInt32Extension ));
+ assertEqualsExactType(102L , message.getExtension(UnittestProto.optionalInt64Extension ));
+ assertEqualsExactType(103 , message.getExtension(UnittestProto.optionalUint32Extension ));
+ assertEqualsExactType(104L , message.getExtension(UnittestProto.optionalUint64Extension ));
+ assertEqualsExactType(105 , message.getExtension(UnittestProto.optionalSint32Extension ));
+ assertEqualsExactType(106L , message.getExtension(UnittestProto.optionalSint64Extension ));
+ assertEqualsExactType(107 , message.getExtension(UnittestProto.optionalFixed32Extension ));
+ assertEqualsExactType(108L , message.getExtension(UnittestProto.optionalFixed64Extension ));
+ assertEqualsExactType(109 , message.getExtension(UnittestProto.optionalSfixed32Extension));
+ assertEqualsExactType(110L , message.getExtension(UnittestProto.optionalSfixed64Extension));
+ assertEqualsExactType(111F , message.getExtension(UnittestProto.optionalFloatExtension ));
+ assertEqualsExactType(112D , message.getExtension(UnittestProto.optionalDoubleExtension ));
+ assertEqualsExactType(true , message.getExtension(UnittestProto.optionalBoolExtension ));
+ assertEqualsExactType("115", message.getExtension(UnittestProto.optionalStringExtension ));
+ assertEqualsExactType(toBytes("116"), message.getExtension(UnittestProto.optionalBytesExtension));
+
+ assertEqualsExactType(117, message.getExtension(UnittestProto.optionalGroupExtension ).getA());
+ assertEqualsExactType(118, message.getExtension(UnittestProto.optionalNestedMessageExtension ).getBb());
+ assertEqualsExactType(119, message.getExtension(UnittestProto.optionalForeignMessageExtension).getC());
+ assertEqualsExactType(120, message.getExtension(UnittestProto.optionalImportMessageExtension ).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+ message.getExtension(UnittestProto.optionalForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+ message.getExtension(UnittestProto.optionalImportEnumExtension));
+
+ assertEqualsExactType("124", message.getExtension(UnittestProto.optionalStringPieceExtension));
+ assertEqualsExactType("125", message.getExtension(UnittestProto.optionalCordExtension));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFloatExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedDoubleExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBoolExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBytesExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedGroupExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedCordExtension));
+
+ assertEqualsExactType(201 , message.getExtension(UnittestProto.repeatedInt32Extension , 0));
+ assertEqualsExactType(202L , message.getExtension(UnittestProto.repeatedInt64Extension , 0));
+ assertEqualsExactType(203 , message.getExtension(UnittestProto.repeatedUint32Extension , 0));
+ assertEqualsExactType(204L , message.getExtension(UnittestProto.repeatedUint64Extension , 0));
+ assertEqualsExactType(205 , message.getExtension(UnittestProto.repeatedSint32Extension , 0));
+ assertEqualsExactType(206L , message.getExtension(UnittestProto.repeatedSint64Extension , 0));
+ assertEqualsExactType(207 , message.getExtension(UnittestProto.repeatedFixed32Extension , 0));
+ assertEqualsExactType(208L , message.getExtension(UnittestProto.repeatedFixed64Extension , 0));
+ assertEqualsExactType(209 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 0));
+ assertEqualsExactType(210L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 0));
+ assertEqualsExactType(211F , message.getExtension(UnittestProto.repeatedFloatExtension , 0));
+ assertEqualsExactType(212D , message.getExtension(UnittestProto.repeatedDoubleExtension , 0));
+ assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 0));
+ assertEqualsExactType("215", message.getExtension(UnittestProto.repeatedStringExtension , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(UnittestProto.repeatedBytesExtension, 0));
+
+ assertEqualsExactType(217, message.getExtension(UnittestProto.repeatedGroupExtension , 0).getA());
+ assertEqualsExactType(218, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 0).getBb());
+ assertEqualsExactType(219, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 0).getC());
+ assertEqualsExactType(220, message.getExtension(UnittestProto.repeatedImportMessageExtension , 0).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(UnittestProto.repeatedForeignEnumExtension, 0));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(UnittestProto.repeatedImportEnumExtension, 0));
+
+ assertEqualsExactType("224", message.getExtension(UnittestProto.repeatedStringPieceExtension, 0));
+ assertEqualsExactType("225", message.getExtension(UnittestProto.repeatedCordExtension, 0));
+
+ assertEqualsExactType(301 , message.getExtension(UnittestProto.repeatedInt32Extension , 1));
+ assertEqualsExactType(302L , message.getExtension(UnittestProto.repeatedInt64Extension , 1));
+ assertEqualsExactType(303 , message.getExtension(UnittestProto.repeatedUint32Extension , 1));
+ assertEqualsExactType(304L , message.getExtension(UnittestProto.repeatedUint64Extension , 1));
+ assertEqualsExactType(305 , message.getExtension(UnittestProto.repeatedSint32Extension , 1));
+ assertEqualsExactType(306L , message.getExtension(UnittestProto.repeatedSint64Extension , 1));
+ assertEqualsExactType(307 , message.getExtension(UnittestProto.repeatedFixed32Extension , 1));
+ assertEqualsExactType(308L , message.getExtension(UnittestProto.repeatedFixed64Extension , 1));
+ assertEqualsExactType(309 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 1));
+ assertEqualsExactType(310L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 1));
+ assertEqualsExactType(311F , message.getExtension(UnittestProto.repeatedFloatExtension , 1));
+ assertEqualsExactType(312D , message.getExtension(UnittestProto.repeatedDoubleExtension , 1));
+ assertEqualsExactType(false, message.getExtension(UnittestProto.repeatedBoolExtension , 1));
+ assertEqualsExactType("315", message.getExtension(UnittestProto.repeatedStringExtension , 1));
+ assertEqualsExactType(toBytes("316"), message.getExtension(UnittestProto.repeatedBytesExtension, 1));
+
+ assertEqualsExactType(317, message.getExtension(UnittestProto.repeatedGroupExtension , 1).getA());
+ assertEqualsExactType(318, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 1).getBb());
+ assertEqualsExactType(319, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 1).getC());
+ assertEqualsExactType(320, message.getExtension(UnittestProto.repeatedImportMessageExtension , 1).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+ message.getExtension(UnittestProto.repeatedForeignEnumExtension, 1));
+ assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+ message.getExtension(UnittestProto.repeatedImportEnumExtension, 1));
+
+ assertEqualsExactType("324", message.getExtension(UnittestProto.repeatedStringPieceExtension, 1));
+ assertEqualsExactType("325", message.getExtension(UnittestProto.repeatedCordExtension, 1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultInt32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultInt64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultUint32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultUint64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultSint32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultSint64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultFixed32Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultFixed64Extension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultSfixed32Extension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultSfixed64Extension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultFloatExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultDoubleExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultBoolExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultStringExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultBytesExtension ));
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultNestedEnumExtension ));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultForeignEnumExtension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultImportEnumExtension ));
+
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultStringPieceExtension));
+ Assert.assertTrue(message.hasExtension(UnittestProto.defaultCordExtension));
+
+ assertEqualsExactType(401 , message.getExtension(UnittestProto.defaultInt32Extension ));
+ assertEqualsExactType(402L , message.getExtension(UnittestProto.defaultInt64Extension ));
+ assertEqualsExactType(403 , message.getExtension(UnittestProto.defaultUint32Extension ));
+ assertEqualsExactType(404L , message.getExtension(UnittestProto.defaultUint64Extension ));
+ assertEqualsExactType(405 , message.getExtension(UnittestProto.defaultSint32Extension ));
+ assertEqualsExactType(406L , message.getExtension(UnittestProto.defaultSint64Extension ));
+ assertEqualsExactType(407 , message.getExtension(UnittestProto.defaultFixed32Extension ));
+ assertEqualsExactType(408L , message.getExtension(UnittestProto.defaultFixed64Extension ));
+ assertEqualsExactType(409 , message.getExtension(UnittestProto.defaultSfixed32Extension));
+ assertEqualsExactType(410L , message.getExtension(UnittestProto.defaultSfixed64Extension));
+ assertEqualsExactType(411F , message.getExtension(UnittestProto.defaultFloatExtension ));
+ assertEqualsExactType(412D , message.getExtension(UnittestProto.defaultDoubleExtension ));
+ assertEqualsExactType(false, message.getExtension(UnittestProto.defaultBoolExtension ));
+ assertEqualsExactType("415", message.getExtension(UnittestProto.defaultStringExtension ));
+ assertEqualsExactType(toBytes("416"), message.getExtension(UnittestProto.defaultBytesExtension));
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(UnittestProto.defaultNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(UnittestProto.defaultForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(UnittestProto.defaultImportEnumExtension));
+
+ assertEqualsExactType("424", message.getExtension(UnittestProto.defaultStringPieceExtension));
+ assertEqualsExactType("425", message.getExtension(UnittestProto.defaultCordExtension));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are cleared, and that getting the extensions returns their
+ * default values.
+ */
+ public static void assertExtensionsClear(TestAllExtensions message) {
+ // hasBlah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalInt32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalInt64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalUint32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalUint64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalSint32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalSint64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalFixed32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalFixed64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalSfixed32Extension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalSfixed64Extension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalFloatExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalDoubleExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalBoolExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalStringExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalBytesExtension ));
+
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalGroupExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalNestedMessageExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalForeignMessageExtension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalImportMessageExtension ));
+
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalNestedEnumExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalForeignEnumExtension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalImportEnumExtension ));
+
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalStringPieceExtension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.optionalCordExtension));
+
+ // Optional fields without defaults are set to zero or something like it.
+ assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalInt32Extension ));
+ assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalInt64Extension ));
+ assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalUint32Extension ));
+ assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalUint64Extension ));
+ assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalSint32Extension ));
+ assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalSint64Extension ));
+ assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalFixed32Extension ));
+ assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalFixed64Extension ));
+ assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalSfixed32Extension));
+ assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalSfixed64Extension));
+ assertEqualsExactType(0F , message.getExtension(UnittestProto.optionalFloatExtension ));
+ assertEqualsExactType(0D , message.getExtension(UnittestProto.optionalDoubleExtension ));
+ assertEqualsExactType(false, message.getExtension(UnittestProto.optionalBoolExtension ));
+ assertEqualsExactType("" , message.getExtension(UnittestProto.optionalStringExtension ));
+ assertEqualsExactType(ByteString.EMPTY, message.getExtension(UnittestProto.optionalBytesExtension));
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(message.getExtension(UnittestProto.optionalGroupExtension ).hasA());
+ Assert.assertFalse(message.getExtension(UnittestProto.optionalNestedMessageExtension ).hasBb());
+ Assert.assertFalse(message.getExtension(UnittestProto.optionalForeignMessageExtension).hasC());
+ Assert.assertFalse(message.getExtension(UnittestProto.optionalImportMessageExtension ).hasD());
+
+ assertEqualsExactType(0, message.getExtension(UnittestProto.optionalGroupExtension ).getA());
+ assertEqualsExactType(0, message.getExtension(UnittestProto.optionalNestedMessageExtension ).getBb());
+ assertEqualsExactType(0, message.getExtension(UnittestProto.optionalForeignMessageExtension).getC());
+ assertEqualsExactType(0, message.getExtension(UnittestProto.optionalImportMessageExtension ).getD());
+
+ // Enums without defaults are set to the first value in the enum.
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(UnittestProto.optionalForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(UnittestProto.optionalImportEnumExtension));
+
+ assertEqualsExactType("", message.getExtension(UnittestProto.optionalStringPieceExtension));
+ assertEqualsExactType("", message.getExtension(UnittestProto.optionalCordExtension));
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedInt32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedInt64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedUint32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedUint64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSint32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSint64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFixed32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFixed64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFloatExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedDoubleExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedBoolExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedStringExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedBytesExtension ));
+
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedGroupExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension ));
+
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension));
+ Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedCordExtension));
+
+ // hasBlah() should also be false for all default fields.
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultInt32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultInt64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultUint32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultUint64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultSint32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultSint64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultFixed32Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultFixed64Extension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultSfixed32Extension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultSfixed64Extension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultFloatExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultDoubleExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultBoolExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultStringExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultBytesExtension ));
+
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultNestedEnumExtension ));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultForeignEnumExtension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultImportEnumExtension ));
+
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultStringPieceExtension));
+ Assert.assertFalse(message.hasExtension(UnittestProto.defaultCordExtension));
+
+ // Fields with defaults have their default values (duh).
+ assertEqualsExactType( 41 , message.getExtension(UnittestProto.defaultInt32Extension ));
+ assertEqualsExactType( 42L , message.getExtension(UnittestProto.defaultInt64Extension ));
+ assertEqualsExactType( 43 , message.getExtension(UnittestProto.defaultUint32Extension ));
+ assertEqualsExactType( 44L , message.getExtension(UnittestProto.defaultUint64Extension ));
+ assertEqualsExactType(-45 , message.getExtension(UnittestProto.defaultSint32Extension ));
+ assertEqualsExactType( 46L , message.getExtension(UnittestProto.defaultSint64Extension ));
+ assertEqualsExactType( 47 , message.getExtension(UnittestProto.defaultFixed32Extension ));
+ assertEqualsExactType( 48L , message.getExtension(UnittestProto.defaultFixed64Extension ));
+ assertEqualsExactType( 49 , message.getExtension(UnittestProto.defaultSfixed32Extension));
+ assertEqualsExactType(-50L , message.getExtension(UnittestProto.defaultSfixed64Extension));
+ assertEqualsExactType( 51.5F , message.getExtension(UnittestProto.defaultFloatExtension ));
+ assertEqualsExactType( 52e3D , message.getExtension(UnittestProto.defaultDoubleExtension ));
+ assertEqualsExactType(true , message.getExtension(UnittestProto.defaultBoolExtension ));
+ assertEqualsExactType("hello", message.getExtension(UnittestProto.defaultStringExtension ));
+ assertEqualsExactType(toBytes("world"), message.getExtension(UnittestProto.defaultBytesExtension));
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.defaultNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(UnittestProto.defaultForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(UnittestProto.defaultImportEnumExtension));
+
+ assertEqualsExactType("abc", message.getExtension(UnittestProto.defaultStringPieceExtension));
+ assertEqualsExactType("123", message.getExtension(UnittestProto.defaultCordExtension));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}
+ * followed by {@code modifyRepeatedExtensions}.
+ */
+ public static void assertRepeatedExtensionsModified(
+ 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.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFloatExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedDoubleExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBoolExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBytesExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedGroupExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension));
+ Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedCordExtension));
+
+ assertEqualsExactType(201 , message.getExtension(UnittestProto.repeatedInt32Extension , 0));
+ assertEqualsExactType(202L , message.getExtension(UnittestProto.repeatedInt64Extension , 0));
+ assertEqualsExactType(203 , message.getExtension(UnittestProto.repeatedUint32Extension , 0));
+ assertEqualsExactType(204L , message.getExtension(UnittestProto.repeatedUint64Extension , 0));
+ assertEqualsExactType(205 , message.getExtension(UnittestProto.repeatedSint32Extension , 0));
+ assertEqualsExactType(206L , message.getExtension(UnittestProto.repeatedSint64Extension , 0));
+ assertEqualsExactType(207 , message.getExtension(UnittestProto.repeatedFixed32Extension , 0));
+ assertEqualsExactType(208L , message.getExtension(UnittestProto.repeatedFixed64Extension , 0));
+ assertEqualsExactType(209 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 0));
+ assertEqualsExactType(210L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 0));
+ assertEqualsExactType(211F , message.getExtension(UnittestProto.repeatedFloatExtension , 0));
+ assertEqualsExactType(212D , message.getExtension(UnittestProto.repeatedDoubleExtension , 0));
+ assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 0));
+ assertEqualsExactType("215", message.getExtension(UnittestProto.repeatedStringExtension , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(UnittestProto.repeatedBytesExtension, 0));
+
+ assertEqualsExactType(217, message.getExtension(UnittestProto.repeatedGroupExtension , 0).getA());
+ assertEqualsExactType(218, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 0).getBb());
+ assertEqualsExactType(219, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 0).getC());
+ assertEqualsExactType(220, message.getExtension(UnittestProto.repeatedImportMessageExtension , 0).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(UnittestProto.repeatedForeignEnumExtension, 0));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(UnittestProto.repeatedImportEnumExtension, 0));
+
+ assertEqualsExactType("224", message.getExtension(UnittestProto.repeatedStringPieceExtension, 0));
+ assertEqualsExactType("225", message.getExtension(UnittestProto.repeatedCordExtension, 0));
+
+ // Actually verify the second (modified) elements now.
+ assertEqualsExactType(501 , message.getExtension(UnittestProto.repeatedInt32Extension , 1));
+ assertEqualsExactType(502L , message.getExtension(UnittestProto.repeatedInt64Extension , 1));
+ assertEqualsExactType(503 , message.getExtension(UnittestProto.repeatedUint32Extension , 1));
+ assertEqualsExactType(504L , message.getExtension(UnittestProto.repeatedUint64Extension , 1));
+ assertEqualsExactType(505 , message.getExtension(UnittestProto.repeatedSint32Extension , 1));
+ assertEqualsExactType(506L , message.getExtension(UnittestProto.repeatedSint64Extension , 1));
+ assertEqualsExactType(507 , message.getExtension(UnittestProto.repeatedFixed32Extension , 1));
+ assertEqualsExactType(508L , message.getExtension(UnittestProto.repeatedFixed64Extension , 1));
+ assertEqualsExactType(509 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 1));
+ assertEqualsExactType(510L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 1));
+ assertEqualsExactType(511F , message.getExtension(UnittestProto.repeatedFloatExtension , 1));
+ assertEqualsExactType(512D , message.getExtension(UnittestProto.repeatedDoubleExtension , 1));
+ assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 1));
+ assertEqualsExactType("515", message.getExtension(UnittestProto.repeatedStringExtension , 1));
+ assertEqualsExactType(toBytes("516"), message.getExtension(UnittestProto.repeatedBytesExtension, 1));
+
+ assertEqualsExactType(517, message.getExtension(UnittestProto.repeatedGroupExtension , 1).getA());
+ assertEqualsExactType(518, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 1).getBb());
+ assertEqualsExactType(519, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 1).getC());
+ assertEqualsExactType(520, message.getExtension(UnittestProto.repeatedImportMessageExtension , 1).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(UnittestProto.repeatedForeignEnumExtension, 1));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(UnittestProto.repeatedImportEnumExtension, 1));
+
+ assertEqualsExactType("524", message.getExtension(UnittestProto.repeatedStringPieceExtension, 1));
+ assertEqualsExactType("525", message.getExtension(UnittestProto.repeatedCordExtension, 1));
+ }
+
+ // ===================================================================
+
+ /**
+ * Performs the same things that the methods of {@code TestUtil} do, but
+ * via the reflection interface. This is its own class because it needs
+ * to know what descriptor to use.
+ */
+ public static class ReflectionTester {
+ private final Descriptors.Descriptor baseDescriptor;
+ private final ExtensionRegistry extensionRegistry;
+
+ private final Descriptors.FileDescriptor file;
+ private final Descriptors.FileDescriptor importFile;
+
+ private final Descriptors.Descriptor optionalGroup;
+ private final Descriptors.Descriptor repeatedGroup;
+ private final Descriptors.Descriptor nestedMessage;
+ private final Descriptors.Descriptor foreignMessage;
+ private final Descriptors.Descriptor importMessage;
+
+ private final Descriptors.FieldDescriptor groupA;
+ private final Descriptors.FieldDescriptor repeatedGroupA;
+ private final Descriptors.FieldDescriptor nestedB;
+ private final Descriptors.FieldDescriptor foreignC;
+ private final Descriptors.FieldDescriptor importD;
+
+ private final Descriptors.EnumDescriptor nestedEnum;
+ private final Descriptors.EnumDescriptor foreignEnum;
+ private final Descriptors.EnumDescriptor importEnum;
+
+ private final Descriptors.EnumValueDescriptor nestedFoo;
+ private final Descriptors.EnumValueDescriptor nestedBar;
+ private final Descriptors.EnumValueDescriptor nestedBaz;
+ private final Descriptors.EnumValueDescriptor foreignFoo;
+ private final Descriptors.EnumValueDescriptor foreignBar;
+ private final Descriptors.EnumValueDescriptor foreignBaz;
+ private final Descriptors.EnumValueDescriptor importFoo;
+ private final Descriptors.EnumValueDescriptor importBar;
+ private final Descriptors.EnumValueDescriptor importBaz;
+
+ /**
+ * Construct a {@code ReflectionTester} that will expect messages using
+ * the given descriptor.
+ *
+ * Normally {@code baseDescriptor} should be a descriptor for the type
+ * {@code TestAllTypes}, defined in
+ * {@code google/protobuf/unittest.proto}. However, if
+ * {@code extensionRegistry} is non-null, then {@code baseDescriptor} should
+ * be for {@code TestAllExtensions} instead, and instead of reading and
+ * writing normal fields, the tester will read and write extensions.
+ * All of {@code TestAllExtensions}' extensions must be registered in the
+ * registry.
+ */
+ public ReflectionTester(Descriptors.Descriptor baseDescriptor,
+ ExtensionRegistry extensionRegistry) {
+ this.baseDescriptor = baseDescriptor;
+ this.extensionRegistry = extensionRegistry;
+
+ this.file = baseDescriptor.getFile();
+ Assert.assertEquals(1, file.getDependencies().size());
+ this.importFile = file.getDependencies().get(0);
+
+ Descriptors.Descriptor testAllTypes;
+ if (extensionRegistry == null) {
+ testAllTypes = baseDescriptor;
+ } else {
+ testAllTypes = file.findMessageTypeByName("TestAllTypes");
+ Assert.assertNotNull(testAllTypes);
+ }
+
+ if (extensionRegistry == null) {
+ this.optionalGroup =
+ baseDescriptor.findNestedTypeByName("OptionalGroup");
+ this.repeatedGroup =
+ baseDescriptor.findNestedTypeByName("RepeatedGroup");
+ } else {
+ this.optionalGroup =
+ file.findMessageTypeByName("OptionalGroup_extension");
+ this.repeatedGroup =
+ file.findMessageTypeByName("RepeatedGroup_extension");
+ }
+ this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
+ this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
+ this.importMessage = importFile.findMessageTypeByName("ImportMessage");
+
+ this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
+ this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
+ this.importEnum = importFile.findEnumTypeByName("ImportEnum");
+
+ Assert.assertNotNull(optionalGroup );
+ Assert.assertNotNull(repeatedGroup );
+ Assert.assertNotNull(nestedMessage );
+ Assert.assertNotNull(foreignMessage);
+ Assert.assertNotNull(importMessage );
+ Assert.assertNotNull(nestedEnum );
+ Assert.assertNotNull(foreignEnum );
+ Assert.assertNotNull(importEnum );
+
+ this.nestedB = nestedMessage .findFieldByName("bb");
+ this.foreignC = foreignMessage.findFieldByName("c");
+ this.importD = importMessage .findFieldByName("d");
+ this.nestedFoo = nestedEnum.findValueByName("FOO");
+ this.nestedBar = nestedEnum.findValueByName("BAR");
+ this.nestedBaz = nestedEnum.findValueByName("BAZ");
+ this.foreignFoo = foreignEnum.findValueByName("FOREIGN_FOO");
+ this.foreignBar = foreignEnum.findValueByName("FOREIGN_BAR");
+ this.foreignBaz = foreignEnum.findValueByName("FOREIGN_BAZ");
+ this.importFoo = importEnum.findValueByName("IMPORT_FOO");
+ this.importBar = importEnum.findValueByName("IMPORT_BAR");
+ this.importBaz = importEnum.findValueByName("IMPORT_BAZ");
+
+ this.groupA = optionalGroup.findFieldByName("a");
+ this.repeatedGroupA = repeatedGroup.findFieldByName("a");
+
+ Assert.assertNotNull(groupA );
+ Assert.assertNotNull(repeatedGroupA);
+ Assert.assertNotNull(nestedB );
+ Assert.assertNotNull(foreignC );
+ Assert.assertNotNull(importD );
+ Assert.assertNotNull(nestedFoo );
+ Assert.assertNotNull(nestedBar );
+ Assert.assertNotNull(nestedBaz );
+ Assert.assertNotNull(foreignFoo );
+ Assert.assertNotNull(foreignBar );
+ Assert.assertNotNull(foreignBaz );
+ Assert.assertNotNull(importFoo );
+ Assert.assertNotNull(importBar );
+ Assert.assertNotNull(importBaz );
+ }
+
+ /**
+ * Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+ */
+ private Descriptors.FieldDescriptor f(String name) {
+ Descriptors.FieldDescriptor result;
+ if (extensionRegistry == null) {
+ result = baseDescriptor.findFieldByName(name);
+ } else {
+ result = file.findExtensionByName(name + "_extension");
+ }
+ Assert.assertNotNull(result);
+ return result;
+ }
+
+ /**
+ * Calls {@code parent.newBuilderForField()} or uses the
+ * {@code ExtensionRegistry} to find an appropriate builder, depending
+ * on what type is being tested.
+ */
+ private Message.Builder newBuilderForField(
+ Message.Builder parent, Descriptors.FieldDescriptor field) {
+ if (extensionRegistry == null) {
+ return parent.newBuilderForField(field);
+ } else {
+ ExtensionRegistry.ExtensionInfo extension =
+ extensionRegistry.findExtensionByNumber(field.getContainingType(),
+ field.getNumber());
+ Assert.assertNotNull(extension);
+ Assert.assertNotNull(extension.defaultInstance);
+ return extension.defaultInstance.newBuilderForType();
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllFieldsSet()}, using the {@link Message.Builder}
+ * reflection interface.
+ */
+ void setAllFieldsViaReflection(Message.Builder message) {
+ message.setField(f("optional_int32" ), 101 );
+ message.setField(f("optional_int64" ), 102L);
+ message.setField(f("optional_uint32" ), 103 );
+ message.setField(f("optional_uint64" ), 104L);
+ message.setField(f("optional_sint32" ), 105 );
+ message.setField(f("optional_sint64" ), 106L);
+ message.setField(f("optional_fixed32" ), 107 );
+ message.setField(f("optional_fixed64" ), 108L);
+ message.setField(f("optional_sfixed32"), 109 );
+ message.setField(f("optional_sfixed64"), 110L);
+ message.setField(f("optional_float" ), 111F);
+ message.setField(f("optional_double" ), 112D);
+ message.setField(f("optional_bool" ), true);
+ message.setField(f("optional_string" ), "115");
+ message.setField(f("optional_bytes" ), toBytes("116"));
+
+ message.setField(f("optionalgroup"),
+ newBuilderForField(message, f("optionalgroup"))
+ .setField(groupA, 117).build());
+ message.setField(f("optional_nested_message"),
+ newBuilderForField(message, f("optional_nested_message"))
+ .setField(nestedB, 118).build());
+ message.setField(f("optional_foreign_message"),
+ newBuilderForField(message, f("optional_foreign_message"))
+ .setField(foreignC, 119).build());
+ message.setField(f("optional_import_message"),
+ newBuilderForField(message, f("optional_import_message"))
+ .setField(importD, 120).build());
+
+ message.setField(f("optional_nested_enum" ), nestedBaz);
+ message.setField(f("optional_foreign_enum"), foreignBaz);
+ message.setField(f("optional_import_enum" ), importBaz);
+
+ message.setField(f("optional_string_piece" ), "124");
+ message.setField(f("optional_cord" ), "125");
+
+ // -----------------------------------------------------------------
+
+ message.addRepeatedField(f("repeated_int32" ), 201 );
+ message.addRepeatedField(f("repeated_int64" ), 202L);
+ message.addRepeatedField(f("repeated_uint32" ), 203 );
+ message.addRepeatedField(f("repeated_uint64" ), 204L);
+ message.addRepeatedField(f("repeated_sint32" ), 205 );
+ message.addRepeatedField(f("repeated_sint64" ), 206L);
+ message.addRepeatedField(f("repeated_fixed32" ), 207 );
+ message.addRepeatedField(f("repeated_fixed64" ), 208L);
+ message.addRepeatedField(f("repeated_sfixed32"), 209 );
+ message.addRepeatedField(f("repeated_sfixed64"), 210L);
+ message.addRepeatedField(f("repeated_float" ), 211F);
+ message.addRepeatedField(f("repeated_double" ), 212D);
+ message.addRepeatedField(f("repeated_bool" ), true);
+ message.addRepeatedField(f("repeated_string" ), "215");
+ message.addRepeatedField(f("repeated_bytes" ), toBytes("216"));
+
+ message.addRepeatedField(f("repeatedgroup"),
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 217).build());
+ message.addRepeatedField(f("repeated_nested_message"),
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 218).build());
+ message.addRepeatedField(f("repeated_foreign_message"),
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 219).build());
+ message.addRepeatedField(f("repeated_import_message"),
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 220).build());
+
+ message.addRepeatedField(f("repeated_nested_enum" ), nestedBar);
+ message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
+ message.addRepeatedField(f("repeated_import_enum" ), importBar);
+
+ message.addRepeatedField(f("repeated_string_piece" ), "224");
+ message.addRepeatedField(f("repeated_cord" ), "225");
+
+ // Add a second one of each field.
+ message.addRepeatedField(f("repeated_int32" ), 301 );
+ message.addRepeatedField(f("repeated_int64" ), 302L);
+ message.addRepeatedField(f("repeated_uint32" ), 303 );
+ message.addRepeatedField(f("repeated_uint64" ), 304L);
+ message.addRepeatedField(f("repeated_sint32" ), 305 );
+ message.addRepeatedField(f("repeated_sint64" ), 306L);
+ message.addRepeatedField(f("repeated_fixed32" ), 307 );
+ message.addRepeatedField(f("repeated_fixed64" ), 308L);
+ message.addRepeatedField(f("repeated_sfixed32"), 309 );
+ message.addRepeatedField(f("repeated_sfixed64"), 310L);
+ message.addRepeatedField(f("repeated_float" ), 311F);
+ message.addRepeatedField(f("repeated_double" ), 312D);
+ message.addRepeatedField(f("repeated_bool" ), false);
+ message.addRepeatedField(f("repeated_string" ), "315");
+ message.addRepeatedField(f("repeated_bytes" ), toBytes("316"));
+
+ message.addRepeatedField(f("repeatedgroup"),
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 317).build());
+ message.addRepeatedField(f("repeated_nested_message"),
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 318).build());
+ message.addRepeatedField(f("repeated_foreign_message"),
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 319).build());
+ message.addRepeatedField(f("repeated_import_message"),
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 320).build());
+
+ message.addRepeatedField(f("repeated_nested_enum" ), nestedBaz);
+ message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
+ message.addRepeatedField(f("repeated_import_enum" ), importBaz);
+
+ message.addRepeatedField(f("repeated_string_piece" ), "324");
+ message.addRepeatedField(f("repeated_cord" ), "325");
+
+ // -----------------------------------------------------------------
+
+ message.setField(f("default_int32" ), 401 );
+ message.setField(f("default_int64" ), 402L);
+ message.setField(f("default_uint32" ), 403 );
+ message.setField(f("default_uint64" ), 404L);
+ message.setField(f("default_sint32" ), 405 );
+ message.setField(f("default_sint64" ), 406L);
+ message.setField(f("default_fixed32" ), 407 );
+ message.setField(f("default_fixed64" ), 408L);
+ message.setField(f("default_sfixed32"), 409 );
+ message.setField(f("default_sfixed64"), 410L);
+ message.setField(f("default_float" ), 411F);
+ message.setField(f("default_double" ), 412D);
+ message.setField(f("default_bool" ), false);
+ message.setField(f("default_string" ), "415");
+ message.setField(f("default_bytes" ), toBytes("416"));
+
+ message.setField(f("default_nested_enum" ), nestedFoo);
+ message.setField(f("default_foreign_enum"), foreignFoo);
+ message.setField(f("default_import_enum" ), importFoo);
+
+ message.setField(f("default_string_piece" ), "424");
+ message.setField(f("default_cord" ), "425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated fields of {@code message} to contain the values
+ * expected by {@code assertRepeatedFieldsModified()}, using the
+ * {@link Message.Builder} reflection interface.
+ */
+ void modifyRepeatedFieldsViaReflection(Message.Builder message) {
+ message.setRepeatedField(f("repeated_int32" ), 1, 501 );
+ message.setRepeatedField(f("repeated_int64" ), 1, 502L);
+ message.setRepeatedField(f("repeated_uint32" ), 1, 503 );
+ message.setRepeatedField(f("repeated_uint64" ), 1, 504L);
+ message.setRepeatedField(f("repeated_sint32" ), 1, 505 );
+ message.setRepeatedField(f("repeated_sint64" ), 1, 506L);
+ message.setRepeatedField(f("repeated_fixed32" ), 1, 507 );
+ message.setRepeatedField(f("repeated_fixed64" ), 1, 508L);
+ message.setRepeatedField(f("repeated_sfixed32"), 1, 509 );
+ message.setRepeatedField(f("repeated_sfixed64"), 1, 510L);
+ message.setRepeatedField(f("repeated_float" ), 1, 511F);
+ message.setRepeatedField(f("repeated_double" ), 1, 512D);
+ message.setRepeatedField(f("repeated_bool" ), 1, true);
+ message.setRepeatedField(f("repeated_string" ), 1, "515");
+ message.setRepeatedField(f("repeated_bytes" ), 1, toBytes("516"));
+
+ message.setRepeatedField(f("repeatedgroup"), 1,
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 517).build());
+ message.setRepeatedField(f("repeated_nested_message"), 1,
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 518).build());
+ message.setRepeatedField(f("repeated_foreign_message"), 1,
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 519).build());
+ message.setRepeatedField(f("repeated_import_message"), 1,
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 520).build());
+
+ message.setRepeatedField(f("repeated_nested_enum" ), 1, nestedFoo);
+ message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
+ message.setRepeatedField(f("repeated_import_enum" ), 1, importFoo);
+
+ message.setRepeatedField(f("repeated_string_piece"), 1, "524");
+ message.setRepeatedField(f("repeated_cord"), 1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields},
+ * using the {@link Message} reflection interface.
+ */
+ public void assertAllFieldsSetViaReflection(Message message) {
+ Assert.assertTrue(message.hasField(f("optional_int32" )));
+ Assert.assertTrue(message.hasField(f("optional_int64" )));
+ Assert.assertTrue(message.hasField(f("optional_uint32" )));
+ Assert.assertTrue(message.hasField(f("optional_uint64" )));
+ Assert.assertTrue(message.hasField(f("optional_sint32" )));
+ Assert.assertTrue(message.hasField(f("optional_sint64" )));
+ Assert.assertTrue(message.hasField(f("optional_fixed32" )));
+ Assert.assertTrue(message.hasField(f("optional_fixed64" )));
+ Assert.assertTrue(message.hasField(f("optional_sfixed32")));
+ Assert.assertTrue(message.hasField(f("optional_sfixed64")));
+ Assert.assertTrue(message.hasField(f("optional_float" )));
+ Assert.assertTrue(message.hasField(f("optional_double" )));
+ Assert.assertTrue(message.hasField(f("optional_bool" )));
+ Assert.assertTrue(message.hasField(f("optional_string" )));
+ Assert.assertTrue(message.hasField(f("optional_bytes" )));
+
+ Assert.assertTrue(message.hasField(f("optionalgroup" )));
+ Assert.assertTrue(message.hasField(f("optional_nested_message" )));
+ Assert.assertTrue(message.hasField(f("optional_foreign_message")));
+ Assert.assertTrue(message.hasField(f("optional_import_message" )));
+
+ Assert.assertTrue(
+ ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_nested_message")))
+ .hasField(nestedB));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_foreign_message")))
+ .hasField(foreignC));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_import_message")))
+ .hasField(importD));
+
+ Assert.assertTrue(message.hasField(f("optional_nested_enum" )));
+ Assert.assertTrue(message.hasField(f("optional_foreign_enum")));
+ Assert.assertTrue(message.hasField(f("optional_import_enum" )));
+
+ Assert.assertTrue(message.hasField(f("optional_string_piece")));
+ Assert.assertTrue(message.hasField(f("optional_cord")));
+
+ Assert.assertEquals(101 , message.getField(f("optional_int32" )));
+ Assert.assertEquals(102L , message.getField(f("optional_int64" )));
+ Assert.assertEquals(103 , message.getField(f("optional_uint32" )));
+ Assert.assertEquals(104L , message.getField(f("optional_uint64" )));
+ Assert.assertEquals(105 , message.getField(f("optional_sint32" )));
+ Assert.assertEquals(106L , message.getField(f("optional_sint64" )));
+ Assert.assertEquals(107 , message.getField(f("optional_fixed32" )));
+ Assert.assertEquals(108L , message.getField(f("optional_fixed64" )));
+ Assert.assertEquals(109 , message.getField(f("optional_sfixed32")));
+ Assert.assertEquals(110L , message.getField(f("optional_sfixed64")));
+ Assert.assertEquals(111F , message.getField(f("optional_float" )));
+ Assert.assertEquals(112D , message.getField(f("optional_double" )));
+ Assert.assertEquals(true , message.getField(f("optional_bool" )));
+ Assert.assertEquals("115", message.getField(f("optional_string" )));
+ Assert.assertEquals(toBytes("116"), message.getField(f("optional_bytes")));
+
+ Assert.assertEquals(117,
+ ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+ Assert.assertEquals(118,
+ ((Message)message.getField(f("optional_nested_message")))
+ .getField(nestedB));
+ Assert.assertEquals(119,
+ ((Message)message.getField(f("optional_foreign_message")))
+ .getField(foreignC));
+ Assert.assertEquals(120,
+ ((Message)message.getField(f("optional_import_message")))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
+ Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
+ Assert.assertEquals( importBaz, message.getField(f("optional_import_enum" )));
+
+ Assert.assertEquals("124", message.getField(f("optional_string_piece")));
+ Assert.assertEquals("125", message.getField(f("optional_cord")));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ Assert.assertEquals(201 , message.getRepeatedField(f("repeated_int32" ), 0));
+ Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64" ), 0));
+ Assert.assertEquals(203 , message.getRepeatedField(f("repeated_uint32" ), 0));
+ Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64" ), 0));
+ Assert.assertEquals(205 , message.getRepeatedField(f("repeated_sint32" ), 0));
+ Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64" ), 0));
+ Assert.assertEquals(207 , message.getRepeatedField(f("repeated_fixed32" ), 0));
+ Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+ Assert.assertEquals(209 , message.getRepeatedField(f("repeated_sfixed32"), 0));
+ Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+ Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float" ), 0));
+ Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double" ), 0));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 0));
+ Assert.assertEquals("215", message.getRepeatedField(f("repeated_string" ), 0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+ Assert.assertEquals(217,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(218,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+ .getField(nestedB));
+ Assert.assertEquals(219,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+ .getField(foreignC));
+ Assert.assertEquals(220,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+ Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+ Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+ Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+ Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+ Assert.assertEquals(301 , message.getRepeatedField(f("repeated_int32" ), 1));
+ Assert.assertEquals(302L , message.getRepeatedField(f("repeated_int64" ), 1));
+ Assert.assertEquals(303 , message.getRepeatedField(f("repeated_uint32" ), 1));
+ Assert.assertEquals(304L , message.getRepeatedField(f("repeated_uint64" ), 1));
+ Assert.assertEquals(305 , message.getRepeatedField(f("repeated_sint32" ), 1));
+ Assert.assertEquals(306L , message.getRepeatedField(f("repeated_sint64" ), 1));
+ Assert.assertEquals(307 , message.getRepeatedField(f("repeated_fixed32" ), 1));
+ Assert.assertEquals(308L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+ Assert.assertEquals(309 , message.getRepeatedField(f("repeated_sfixed32"), 1));
+ Assert.assertEquals(310L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+ Assert.assertEquals(311F , message.getRepeatedField(f("repeated_float" ), 1));
+ Assert.assertEquals(312D , message.getRepeatedField(f("repeated_double" ), 1));
+ Assert.assertEquals(false, message.getRepeatedField(f("repeated_bool" ), 1));
+ Assert.assertEquals("315", message.getRepeatedField(f("repeated_string" ), 1));
+ Assert.assertEquals(toBytes("316"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+ Assert.assertEquals(317,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(318,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+ .getField(nestedB));
+ Assert.assertEquals(319,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+ .getField(foreignC));
+ Assert.assertEquals(320,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
+ Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
+ Assert.assertEquals( importBaz, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+ Assert.assertEquals("324", message.getRepeatedField(f("repeated_string_piece"), 1));
+ Assert.assertEquals("325", message.getRepeatedField(f("repeated_cord"), 1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasField(f("default_int32" )));
+ Assert.assertTrue(message.hasField(f("default_int64" )));
+ Assert.assertTrue(message.hasField(f("default_uint32" )));
+ Assert.assertTrue(message.hasField(f("default_uint64" )));
+ Assert.assertTrue(message.hasField(f("default_sint32" )));
+ Assert.assertTrue(message.hasField(f("default_sint64" )));
+ Assert.assertTrue(message.hasField(f("default_fixed32" )));
+ Assert.assertTrue(message.hasField(f("default_fixed64" )));
+ Assert.assertTrue(message.hasField(f("default_sfixed32")));
+ Assert.assertTrue(message.hasField(f("default_sfixed64")));
+ Assert.assertTrue(message.hasField(f("default_float" )));
+ Assert.assertTrue(message.hasField(f("default_double" )));
+ Assert.assertTrue(message.hasField(f("default_bool" )));
+ Assert.assertTrue(message.hasField(f("default_string" )));
+ Assert.assertTrue(message.hasField(f("default_bytes" )));
+
+ Assert.assertTrue(message.hasField(f("default_nested_enum" )));
+ Assert.assertTrue(message.hasField(f("default_foreign_enum")));
+ Assert.assertTrue(message.hasField(f("default_import_enum" )));
+
+ Assert.assertTrue(message.hasField(f("default_string_piece")));
+ Assert.assertTrue(message.hasField(f("default_cord")));
+
+ Assert.assertEquals(401 , message.getField(f("default_int32" )));
+ Assert.assertEquals(402L , message.getField(f("default_int64" )));
+ Assert.assertEquals(403 , message.getField(f("default_uint32" )));
+ Assert.assertEquals(404L , message.getField(f("default_uint64" )));
+ Assert.assertEquals(405 , message.getField(f("default_sint32" )));
+ Assert.assertEquals(406L , message.getField(f("default_sint64" )));
+ Assert.assertEquals(407 , message.getField(f("default_fixed32" )));
+ Assert.assertEquals(408L , message.getField(f("default_fixed64" )));
+ Assert.assertEquals(409 , message.getField(f("default_sfixed32")));
+ Assert.assertEquals(410L , message.getField(f("default_sfixed64")));
+ Assert.assertEquals(411F , message.getField(f("default_float" )));
+ Assert.assertEquals(412D , message.getField(f("default_double" )));
+ Assert.assertEquals(false, message.getField(f("default_bool" )));
+ Assert.assertEquals("415", message.getField(f("default_string" )));
+ Assert.assertEquals(toBytes("416"), message.getField(f("default_bytes")));
+
+ Assert.assertEquals( nestedFoo, message.getField(f("default_nested_enum" )));
+ Assert.assertEquals(foreignFoo, message.getField(f("default_foreign_enum")));
+ Assert.assertEquals( importFoo, message.getField(f("default_import_enum" )));
+
+ Assert.assertEquals("424", message.getField(f("default_string_piece")));
+ Assert.assertEquals("425", message.getField(f("default_cord")));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are cleared, and that getting the fields returns their
+ * default values, using the {@link Message} reflection interface.
+ */
+ public void assertClearViaReflection(Message message) {
+ // has_blah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasField(f("optional_int32" )));
+ Assert.assertFalse(message.hasField(f("optional_int64" )));
+ Assert.assertFalse(message.hasField(f("optional_uint32" )));
+ Assert.assertFalse(message.hasField(f("optional_uint64" )));
+ Assert.assertFalse(message.hasField(f("optional_sint32" )));
+ Assert.assertFalse(message.hasField(f("optional_sint64" )));
+ Assert.assertFalse(message.hasField(f("optional_fixed32" )));
+ Assert.assertFalse(message.hasField(f("optional_fixed64" )));
+ Assert.assertFalse(message.hasField(f("optional_sfixed32")));
+ Assert.assertFalse(message.hasField(f("optional_sfixed64")));
+ Assert.assertFalse(message.hasField(f("optional_float" )));
+ Assert.assertFalse(message.hasField(f("optional_double" )));
+ Assert.assertFalse(message.hasField(f("optional_bool" )));
+ Assert.assertFalse(message.hasField(f("optional_string" )));
+ Assert.assertFalse(message.hasField(f("optional_bytes" )));
+
+ Assert.assertFalse(message.hasField(f("optionalgroup" )));
+ Assert.assertFalse(message.hasField(f("optional_nested_message" )));
+ Assert.assertFalse(message.hasField(f("optional_foreign_message")));
+ Assert.assertFalse(message.hasField(f("optional_import_message" )));
+
+ Assert.assertFalse(message.hasField(f("optional_nested_enum" )));
+ Assert.assertFalse(message.hasField(f("optional_foreign_enum")));
+ Assert.assertFalse(message.hasField(f("optional_import_enum" )));
+
+ Assert.assertFalse(message.hasField(f("optional_string_piece")));
+ Assert.assertFalse(message.hasField(f("optional_cord")));
+
+ // Optional fields without defaults are set to zero or something like it.
+ Assert.assertEquals(0 , message.getField(f("optional_int32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_int64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_uint32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_uint64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_sint32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_sint64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_fixed32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_fixed64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_sfixed32")));
+ Assert.assertEquals(0L , message.getField(f("optional_sfixed64")));
+ Assert.assertEquals(0F , message.getField(f("optional_float" )));
+ Assert.assertEquals(0D , message.getField(f("optional_double" )));
+ Assert.assertEquals(false, message.getField(f("optional_bool" )));
+ Assert.assertEquals("" , message.getField(f("optional_string" )));
+ Assert.assertEquals(ByteString.EMPTY, message.getField(f("optional_bytes")));
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(
+ ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_nested_message")))
+ .hasField(nestedB));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_foreign_message")))
+ .hasField(foreignC));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_import_message")))
+ .hasField(importD));
+
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_nested_message")))
+ .getField(nestedB));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_foreign_message")))
+ .getField(foreignC));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_import_message")))
+ .getField(importD));
+
+ // Enums without defaults are set to the first value in the enum.
+ Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
+ Assert.assertEquals(foreignFoo, message.getField(f("optional_foreign_enum")));
+ Assert.assertEquals( importFoo, message.getField(f("optional_import_enum" )));
+
+ Assert.assertEquals("", message.getField(f("optional_string_piece")));
+ Assert.assertEquals("", message.getField(f("optional_cord")));
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ // has_blah() should also be false for all default fields.
+ Assert.assertFalse(message.hasField(f("default_int32" )));
+ Assert.assertFalse(message.hasField(f("default_int64" )));
+ Assert.assertFalse(message.hasField(f("default_uint32" )));
+ Assert.assertFalse(message.hasField(f("default_uint64" )));
+ Assert.assertFalse(message.hasField(f("default_sint32" )));
+ Assert.assertFalse(message.hasField(f("default_sint64" )));
+ Assert.assertFalse(message.hasField(f("default_fixed32" )));
+ Assert.assertFalse(message.hasField(f("default_fixed64" )));
+ Assert.assertFalse(message.hasField(f("default_sfixed32")));
+ Assert.assertFalse(message.hasField(f("default_sfixed64")));
+ Assert.assertFalse(message.hasField(f("default_float" )));
+ Assert.assertFalse(message.hasField(f("default_double" )));
+ Assert.assertFalse(message.hasField(f("default_bool" )));
+ Assert.assertFalse(message.hasField(f("default_string" )));
+ Assert.assertFalse(message.hasField(f("default_bytes" )));
+
+ Assert.assertFalse(message.hasField(f("default_nested_enum" )));
+ Assert.assertFalse(message.hasField(f("default_foreign_enum")));
+ Assert.assertFalse(message.hasField(f("default_import_enum" )));
+
+ Assert.assertFalse(message.hasField(f("default_string_piece" )));
+ Assert.assertFalse(message.hasField(f("default_cord" )));
+
+ // Fields with defaults have their default values (duh).
+ Assert.assertEquals( 41 , message.getField(f("default_int32" )));
+ Assert.assertEquals( 42L , message.getField(f("default_int64" )));
+ Assert.assertEquals( 43 , message.getField(f("default_uint32" )));
+ Assert.assertEquals( 44L , message.getField(f("default_uint64" )));
+ Assert.assertEquals(-45 , message.getField(f("default_sint32" )));
+ Assert.assertEquals( 46L , message.getField(f("default_sint64" )));
+ Assert.assertEquals( 47 , message.getField(f("default_fixed32" )));
+ Assert.assertEquals( 48L , message.getField(f("default_fixed64" )));
+ Assert.assertEquals( 49 , message.getField(f("default_sfixed32")));
+ Assert.assertEquals(-50L , message.getField(f("default_sfixed64")));
+ Assert.assertEquals( 51.5F , message.getField(f("default_float" )));
+ Assert.assertEquals( 52e3D , message.getField(f("default_double" )));
+ Assert.assertEquals(true , message.getField(f("default_bool" )));
+ Assert.assertEquals("hello", message.getField(f("default_string" )));
+ Assert.assertEquals(toBytes("world"), message.getField(f("default_bytes")));
+
+ Assert.assertEquals( nestedBar, message.getField(f("default_nested_enum" )));
+ Assert.assertEquals(foreignBar, message.getField(f("default_foreign_enum")));
+ Assert.assertEquals( importBar, message.getField(f("default_import_enum" )));
+
+ Assert.assertEquals("abc", message.getField(f("default_string_piece")));
+ Assert.assertEquals("123", message.getField(f("default_cord")));
+ }
+
+ // ---------------------------------------------------------------
+
+ public void assertRepeatedFieldsModifiedViaReflection(Message message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ Assert.assertEquals(201 , message.getRepeatedField(f("repeated_int32" ), 0));
+ Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64" ), 0));
+ Assert.assertEquals(203 , message.getRepeatedField(f("repeated_uint32" ), 0));
+ Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64" ), 0));
+ Assert.assertEquals(205 , message.getRepeatedField(f("repeated_sint32" ), 0));
+ Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64" ), 0));
+ Assert.assertEquals(207 , message.getRepeatedField(f("repeated_fixed32" ), 0));
+ Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+ Assert.assertEquals(209 , message.getRepeatedField(f("repeated_sfixed32"), 0));
+ Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+ Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float" ), 0));
+ Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double" ), 0));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 0));
+ Assert.assertEquals("215", message.getRepeatedField(f("repeated_string" ), 0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+ Assert.assertEquals(217,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(218,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+ .getField(nestedB));
+ Assert.assertEquals(219,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+ .getField(foreignC));
+ Assert.assertEquals(220,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+ Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+ Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+ Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+ Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+ Assert.assertEquals(501 , message.getRepeatedField(f("repeated_int32" ), 1));
+ Assert.assertEquals(502L , message.getRepeatedField(f("repeated_int64" ), 1));
+ Assert.assertEquals(503 , message.getRepeatedField(f("repeated_uint32" ), 1));
+ Assert.assertEquals(504L , message.getRepeatedField(f("repeated_uint64" ), 1));
+ Assert.assertEquals(505 , message.getRepeatedField(f("repeated_sint32" ), 1));
+ Assert.assertEquals(506L , message.getRepeatedField(f("repeated_sint64" ), 1));
+ Assert.assertEquals(507 , message.getRepeatedField(f("repeated_fixed32" ), 1));
+ Assert.assertEquals(508L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+ Assert.assertEquals(509 , message.getRepeatedField(f("repeated_sfixed32"), 1));
+ Assert.assertEquals(510L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+ Assert.assertEquals(511F , message.getRepeatedField(f("repeated_float" ), 1));
+ Assert.assertEquals(512D , message.getRepeatedField(f("repeated_double" ), 1));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 1));
+ Assert.assertEquals("515", message.getRepeatedField(f("repeated_string" ), 1));
+ Assert.assertEquals(toBytes("516"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+ Assert.assertEquals(517,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(518,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+ .getField(nestedB));
+ Assert.assertEquals(519,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+ .getField(foreignC));
+ Assert.assertEquals(520,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+ .getField(importD));
+
+ Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
+ Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
+ Assert.assertEquals( importFoo, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+ Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1));
+ Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1));
+ }
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static String readTextFromFile(String filePath) {
+ return readBytesFromFile(filePath).toStringUtf8();
+ }
+
+ private static File getTestDataDir() {
+ // Search each parent directory looking for "src/google/protobuf".
+ File ancestor = new File(".");
+ try {
+ ancestor = ancestor.getCanonicalFile();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Couldn't get canonical name of working directory.", e);
+ }
+ while (ancestor != null && ancestor.exists()) {
+ if (new File(ancestor, "src/google/protobuf").exists()) {
+ return new File(ancestor, "src/google/protobuf/testdata");
+ }
+ ancestor = ancestor.getParentFile();
+ }
+
+ throw new RuntimeException(
+ "Could not find golden files. This test must be run from within the " +
+ "protobuf source package so that it can read test data files from the " +
+ "C++ source tree.");
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static ByteString readBytesFromFile(String filename) {
+ File fullPath = new File(getTestDataDir(), filename);
+ try {
+ RandomAccessFile file = new RandomAccessFile(fullPath, "r");
+ byte[] content = new byte[(int) file.length()];
+ file.readFully(content);
+ return ByteString.copyFrom(content);
+ } catch (IOException e) {
+ // Throw a RuntimeException here so that we can call this function from
+ // static initializers.
+ throw new IllegalArgumentException(
+ "Couldn't read file: " + fullPath.getPath(), e);
+ }
+ }
+
+ /**
+ * Get the bytes of the "golden message". This is a serialized TestAllTypes
+ * with all fields set as they would be by
+ * {@link setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
+ * on disk rather than generated dynamically. The file is actually generated
+ * by C++ code, so testing against it verifies compatibility with C++.
+ */
+ public static ByteString getGoldenMessage() {
+ if (goldenMessage == null) {
+ goldenMessage = readBytesFromFile("golden_message");
+ }
+ return goldenMessage;
+ }
+ private static ByteString goldenMessage = null;
+}
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
new file mode 100644
index 00000000..2c485c55
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -0,0 +1,534 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+
+/**
+ * Test case for {@link TextFormat}.
+ *
+ * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
+ *
+ * @author wenboz@google.com (Wenbo Zhu)
+ */
+public class TextFormatTest extends TestCase {
+
+ // A basic string with different escapable characters for testing.
+ private final static String kEscapeTestString =
+ "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+ + "slashes \\";
+
+ // A representation of the above string with all the characters escaped.
+ private final static String kEscapeTestStringEscaped =
+ "\"\\\"A string with \\' characters \\n and \\r newlines "
+ + "and \\t tabs and \\001 slashes \\\\\"";
+
+ private static String allFieldsSetText = TestUtil.readTextFromFile(
+ "text_format_unittest_data.txt");
+ private static String allExtensionsSetText = TestUtil.readTextFromFile(
+ "text_format_unittest_extensions_data.txt");
+
+ private String exoticText =
+ "repeated_int32: -1\n" +
+ "repeated_int32: -2147483648\n" +
+ "repeated_int64: -1\n" +
+ "repeated_int64: -9223372036854775808\n" +
+ "repeated_uint32: 4294967295\n" +
+ "repeated_uint32: 2147483648\n" +
+ "repeated_uint64: 18446744073709551615\n" +
+ "repeated_uint64: 9223372036854775808\n" +
+ "repeated_double: 123.0\n" +
+ "repeated_double: 123.5\n" +
+ "repeated_double: 0.125\n" +
+ "repeated_double: 1.23E17\n" +
+ "repeated_double: 1.235E22\n" +
+ "repeated_double: 1.235E-18\n" +
+ "repeated_double: 123.456789\n" +
+ "repeated_double: Infinity\n" +
+ "repeated_double: -Infinity\n" +
+ "repeated_double: NaN\n" +
+ "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
+ "\\341\\210\\264\"\n" +
+ "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
+
+ private String messageSetText =
+ "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+ " i: 123\n" +
+ "}\n" +
+ "[protobuf_unittest.TestMessageSetExtension2] {\n" +
+ " str: \"foo\"\n" +
+ "}\n";
+
+ /** Print TestAllTypes and compare with golden file. */
+ public void testPrintMessage() throws Exception {
+ String javaText = TextFormat.printToString(TestUtil.getAllSet());
+
+ // Java likes to add a trailing ".0" to floats and doubles. C printf
+ // (with %g format) does not. Our golden files are used for both
+ // C++ and Java TextFormat classes, so we need to conform.
+ javaText = javaText.replace(".0\n", "\n");
+
+ assertEquals(allFieldsSetText, javaText);
+ }
+
+ /** Print TestAllExtensions and compare with golden file. */
+ public void testPrintExtensions() throws Exception {
+ String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
+
+ // Java likes to add a trailing ".0" to floats and doubles. C printf
+ // (with %g format) does not. Our golden files are used for both
+ // C++ and Java TextFormat classes, so we need to conform.
+ javaText = javaText.replace(".0\n", "\n");
+
+ assertEquals(allExtensionsSetText, javaText);
+ }
+
+ public void testPrintUnknownFields() throws Exception {
+ // Test printing of unknown fields in a message.
+
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(5,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1)
+ .addFixed32(2)
+ .addFixed64(3)
+ .addLengthDelimited(ByteString.copyFromUtf8("4"))
+ .addGroup(
+ UnknownFieldSet.newBuilder()
+ .addField(10,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(5)
+ .build())
+ .build())
+ .build())
+ .addField(8,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1)
+ .addVarint(2)
+ .addVarint(3)
+ .build())
+ .addField(15,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(0xABCDEF1234567890L)
+ .addFixed32(0xABCD1234)
+ .addFixed64(0xABCDEF1234567890L)
+ .build())
+ .build())
+ .build();
+
+ assertEquals(
+ "5: 1\n" +
+ "5: 0x00000002\n" +
+ "5: 0x0000000000000003\n" +
+ "5: \"4\"\n" +
+ "5 {\n" +
+ " 10: 5\n" +
+ "}\n" +
+ "8: 1\n" +
+ "8: 2\n" +
+ "8: 3\n" +
+ "15: 12379813812177893520\n" +
+ "15: 0xabcd1234\n" +
+ "15: 0xabcdef1234567890\n",
+ TextFormat.printToString(message));
+ }
+
+ /**
+ * Helper to construct a ByteString from a String containing only 8-bit
+ * characters. The characters are converted directly to bytes, *not*
+ * encoded using UTF-8.
+ */
+ private ByteString bytes(String str) throws Exception {
+ return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
+ }
+
+ /**
+ * Helper to construct a ByteString from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private ByteString bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return ByteString.copyFrom(bytes);
+ }
+
+ public void testPrintExotic() throws Exception {
+ Message message = TestAllTypes.newBuilder()
+ // Signed vs. unsigned numbers.
+ .addRepeatedInt32 (-1)
+ .addRepeatedUint32(-1)
+ .addRepeatedInt64 (-1)
+ .addRepeatedUint64(-1)
+
+ .addRepeatedInt32 (1 << 31)
+ .addRepeatedUint32(1 << 31)
+ .addRepeatedInt64 (1l << 63)
+ .addRepeatedUint64(1l << 63)
+
+ // Floats of various precisions and exponents.
+ .addRepeatedDouble(123)
+ .addRepeatedDouble(123.5)
+ .addRepeatedDouble(0.125)
+ .addRepeatedDouble(123e15)
+ .addRepeatedDouble(123.5e20)
+ .addRepeatedDouble(123.5e-20)
+ .addRepeatedDouble(123.456789)
+ .addRepeatedDouble(Double.POSITIVE_INFINITY)
+ .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+ .addRepeatedDouble(Double.NaN)
+
+ // Strings and bytes that needing escaping.
+ .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
+ .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
+ .build();
+
+ assertEquals(exoticText, message.toString());
+ }
+
+ public void testPrintMessageSet() throws Exception {
+ TestMessageSet messageSet =
+ TestMessageSet.newBuilder()
+ .setExtension(
+ TestMessageSetExtension1.messageSetExtension,
+ TestMessageSetExtension1.newBuilder().setI(123).build())
+ .setExtension(
+ TestMessageSetExtension2.messageSetExtension,
+ TestMessageSetExtension2.newBuilder().setStr("foo").build())
+ .build();
+
+ assertEquals(messageSetText, messageSet.toString());
+ }
+
+ // =================================================================
+
+ public void testParse() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(allFieldsSetText, builder);
+ TestUtil.assertAllFieldsSet(builder.build());
+ }
+
+ public void testParseReader() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(new StringReader(allFieldsSetText), builder);
+ TestUtil.assertAllFieldsSet(builder.build());
+ }
+
+ public void testParseExtensions() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TextFormat.merge(allExtensionsSetText,
+ TestUtil.getExtensionRegistry(),
+ builder);
+ TestUtil.assertAllExtensionsSet(builder.build());
+ }
+
+ public void testParseExotic() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(exoticText, builder);
+
+ // Too lazy to check things individually. Don't try to debug this
+ // if testPrintExotic() is failing.
+ assertEquals(exoticText, builder.build().toString());
+ }
+
+ public void testParseMessageSet() throws Exception {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+ extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+ TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+ TextFormat.merge(messageSetText, extensionRegistry, builder);
+ TestMessageSet messageSet = builder.build();
+
+ assertTrue(messageSet.hasExtension(
+ TestMessageSetExtension1.messageSetExtension));
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ assertTrue(messageSet.hasExtension(
+ TestMessageSetExtension2.messageSetExtension));
+ assertEquals("foo", messageSet.getExtension(
+ TestMessageSetExtension2.messageSetExtension).getStr());
+ }
+
+ public void testParseNumericEnum() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("optional_nested_enum: 2", builder);
+ assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
+ }
+
+ public void testParseAngleBrackets() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("OptionalGroup: < a: 1 >", builder);
+ assertTrue(builder.hasOptionalGroup());
+ assertEquals(1, builder.getOptionalGroup().getA());
+ }
+
+ private void assertParseError(String error, String text) {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals(error, e.getMessage());
+ }
+ }
+
+ public void testParseErrors() throws Exception {
+ assertParseError(
+ "1:16: Expected \":\".",
+ "optional_int32 123");
+ assertParseError(
+ "1:23: Expected identifier.",
+ "optional_nested_enum: ?");
+ assertParseError(
+ "1:18: Couldn't parse integer: Number must be positive: -1",
+ "optional_uint32: -1");
+ assertParseError(
+ "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
+ "integer: 82301481290849012385230157",
+ "optional_int32: 82301481290849012385230157");
+ assertParseError(
+ "1:16: Expected \"true\" or \"false\".",
+ "optional_bool: maybe");
+ assertParseError(
+ "1:18: Expected string.",
+ "optional_string: 123");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe\n" +
+ "optional_int32: 123");
+ assertParseError(
+ "1:18: Invalid escape sequence: '\\z'",
+ "optional_string: \"\\z\"");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe\n" +
+ "optional_int32: 123");
+ assertParseError(
+ "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
+ "[nosuchext]: 123");
+ assertParseError(
+ "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
+ "not extend message type \"protobuf_unittest.TestAllTypes\".",
+ "[protobuf_unittest.optional_int32_extension]: 123");
+ assertParseError(
+ "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
+ "named \"nosuchfield\".",
+ "nosuchfield: 123");
+ assertParseError(
+ "1:21: Expected \">\".",
+ "OptionalGroup < a: 1");
+ assertParseError(
+ "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+ "value named \"NO_SUCH_VALUE\".",
+ "optional_nested_enum: NO_SUCH_VALUE");
+ assertParseError(
+ "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+ "value with number 123.",
+ "optional_nested_enum: 123");
+
+ // Delimiters must match.
+ assertParseError(
+ "1:22: Expected identifier.",
+ "OptionalGroup < a: 1 }");
+ assertParseError(
+ "1:22: Expected identifier.",
+ "OptionalGroup { a: 1 >");
+ }
+
+ // =================================================================
+
+ public void testEscape() throws Exception {
+ // Escape sequences.
+ assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
+ TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"")));
+ assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
+ TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\""));
+ assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
+ TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+ assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
+ TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+
+ // Unicode handling.
+ assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
+ assertEquals("\\341\\210\\264",
+ TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
+ assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
+ assertEquals(bytes(0xe1, 0x88, 0xb4),
+ TextFormat.unescapeBytes("\\341\\210\\264"));
+ assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
+ assertEquals(bytes(0xe1, 0x88, 0xb4),
+ TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
+
+ // Errors.
+ try {
+ TextFormat.unescapeText("\\x");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequence e) {
+ // success
+ }
+
+ try {
+ TextFormat.unescapeText("\\z");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequence e) {
+ // success
+ }
+
+ try {
+ TextFormat.unescapeText("\\");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequence e) {
+ // success
+ }
+ }
+
+ public void testParseInteger() throws Exception {
+ assertEquals( 0, TextFormat.parseInt32( "0"));
+ assertEquals( 1, TextFormat.parseInt32( "1"));
+ assertEquals( -1, TextFormat.parseInt32( "-1"));
+ assertEquals( 12345, TextFormat.parseInt32( "12345"));
+ assertEquals( -12345, TextFormat.parseInt32( "-12345"));
+ assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
+ assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
+
+ assertEquals( 0, TextFormat.parseUInt32( "0"));
+ assertEquals( 1, TextFormat.parseUInt32( "1"));
+ assertEquals( 12345, TextFormat.parseUInt32( "12345"));
+ assertEquals( 2147483647, TextFormat.parseUInt32("2147483647"));
+ assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
+ assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
+
+ assertEquals( 0L, TextFormat.parseInt64( "0"));
+ assertEquals( 1L, TextFormat.parseInt64( "1"));
+ assertEquals( -1L, TextFormat.parseInt64( "-1"));
+ assertEquals( 12345L, TextFormat.parseInt64( "12345"));
+ assertEquals( -12345L, TextFormat.parseInt64( "-12345"));
+ assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
+ assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
+ assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
+ assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
+ assertEquals(9223372036854775807L,
+ TextFormat.parseInt64("9223372036854775807"));
+ assertEquals(-9223372036854775808L,
+ TextFormat.parseInt64("-9223372036854775808"));
+
+ assertEquals( 0L, TextFormat.parseUInt64( "0"));
+ assertEquals( 1L, TextFormat.parseUInt64( "1"));
+ assertEquals( 12345L, TextFormat.parseUInt64( "12345"));
+ assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
+ assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
+ assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
+ assertEquals(9223372036854775807L,
+ TextFormat.parseUInt64("9223372036854775807"));
+ assertEquals(-9223372036854775808L,
+ TextFormat.parseUInt64("9223372036854775808"));
+ assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
+
+ // Hex
+ assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
+ assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
+ assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
+ assertEquals(0x7fffffffffffffffL,
+ TextFormat.parseInt64("0x7fffffffffffffff"));
+
+ // Octal
+ assertEquals(01234567, TextFormat.parseInt32("01234567"));
+
+ // Out-of-range
+ try {
+ TextFormat.parseInt32("2147483648");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt32("-2147483649");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt32("4294967296");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt32("-1");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt64("9223372036854775808");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt64("-9223372036854775809");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt64("18446744073709551616");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt64("-1");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ // Not a number.
+ try {
+ TextFormat.parseInt32("abcd");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
new file mode 100644
index 00000000..0ad2683d
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -0,0 +1,315 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.
+ TestEmptyMessageWithExtensions;
+
+import junit.framework.TestCase;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests related to unknown field handling.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class UnknownFieldSetTest extends TestCase {
+ public void setUp() throws Exception {
+ descriptor = TestAllTypes.getDescriptor();
+ allFields = TestUtil.getAllSet();
+ allFieldsData = allFields.toByteString();
+ emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+ unknownFields = emptyMessage.getUnknownFields();
+ }
+
+ UnknownFieldSet.Field getField(String name) {
+ Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
+ assertNotNull(field);
+ return unknownFields.getField(field.getNumber());
+ }
+
+ // Constructs a protocol buffer which contains fields with all the same
+ // numbers as allFieldsData except that each field is some other wire
+ // type.
+ ByteString getBizarroData() throws Exception {
+ UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+ UnknownFieldSet.Field varintField =
+ UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+ UnknownFieldSet.Field fixed32Field =
+ UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+ for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+ unknownFields.asMap().entrySet()) {
+ if (entry.getValue().getVarintList().isEmpty()) {
+ // Original field is not a varint, so use a varint.
+ bizarroFields.addField(entry.getKey(), varintField);
+ } else {
+ // Original field *is* a varint, so use something else.
+ bizarroFields.addField(entry.getKey(), fixed32Field);
+ }
+ }
+
+ return bizarroFields.build().toByteString();
+ }
+
+ Descriptors.Descriptor descriptor;
+ TestAllTypes allFields;
+ ByteString allFieldsData;
+
+ // An empty message that has been parsed from allFieldsData. So, it has
+ // unknown fields of every type.
+ TestEmptyMessage emptyMessage;
+ UnknownFieldSet unknownFields;
+
+ // =================================================================
+
+ public void testVarint() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_int32");
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(allFields.getOptionalInt32(),
+ (long) field.getVarintList().get(0));
+ }
+
+ public void testFixed32() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_fixed32");
+ assertEquals(1, field.getFixed32List().size());
+ assertEquals(allFields.getOptionalFixed32(),
+ (int) field.getFixed32List().get(0));
+ }
+
+ public void testFixed64() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_fixed64");
+ assertEquals(1, field.getFixed64List().size());
+ assertEquals(allFields.getOptionalFixed64(),
+ (long) field.getFixed64List().get(0));
+ }
+
+ public void testLengthDelimited() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_bytes");
+ assertEquals(1, field.getLengthDelimitedList().size());
+ assertEquals(allFields.getOptionalBytes(),
+ field.getLengthDelimitedList().get(0));
+ }
+
+ public void testGroup() throws Exception {
+ Descriptors.FieldDescriptor nestedFieldDescriptor =
+ TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
+ assertNotNull(nestedFieldDescriptor);
+
+ UnknownFieldSet.Field field = getField("optionalgroup");
+ assertEquals(1, field.getGroupList().size());
+
+ UnknownFieldSet group = field.getGroupList().get(0);
+ assertEquals(1, group.asMap().size());
+ assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
+
+ UnknownFieldSet.Field nestedField =
+ group.getField(nestedFieldDescriptor.getNumber());
+ assertEquals(1, nestedField.getVarintList().size());
+ assertEquals(allFields.getOptionalGroup().getA(),
+ (long) nestedField.getVarintList().get(0));
+ }
+
+ public void testSerialize() throws Exception {
+ // Check that serializing the UnknownFieldSet produces the original data
+ // again.
+ ByteString data = emptyMessage.toByteString();
+ assertEquals(allFieldsData, data);
+ }
+
+ public void testCopyFrom() throws Exception {
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
+
+ assertEquals(emptyMessage.toString(), message.toString());
+ }
+
+ public void testMergeFrom() throws Exception {
+ TestEmptyMessage source =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(2,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(2).build())
+ .addField(3,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(4).build())
+ .build())
+ .build();
+ TestEmptyMessage destination =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(1,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1).build())
+ .addField(3,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(3).build())
+ .build())
+ .mergeFrom(source)
+ .build();
+
+ assertEquals(
+ "1: 1\n" +
+ "2: 2\n" +
+ "3: 3\n" +
+ "3: 4\n",
+ destination.toString());
+ }
+
+ public void testClear() throws Exception {
+ UnknownFieldSet fields =
+ UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
+ assertTrue(fields.asMap().isEmpty());
+ }
+
+ public void testClearMessage() throws Exception {
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
+ assertEquals(0, message.getSerializedSize());
+ }
+
+ public void testParseKnownAndUnknown() throws Exception {
+ // Test mixing known and unknown fields when parsing.
+
+ UnknownFieldSet fields =
+ UnknownFieldSet.newBuilder(unknownFields)
+ .addField(123456,
+ UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
+ .build();
+
+ ByteString data = fields.toByteString();
+ TestAllTypes destination = TestAllTypes.parseFrom(data);
+
+ TestUtil.assertAllFieldsSet(destination);
+ assertEquals(1, destination.getUnknownFields().asMap().size());
+
+ UnknownFieldSet.Field field =
+ destination.getUnknownFields().getField(123456);
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(654321, (long) field.getVarintList().get(0));
+ }
+
+ public void testWrongTypeTreatedAsUnknown() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+ TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the debug strings
+ // should be the same.
+ assertEquals(emptyMessage.toString(), allTypesMessage.toString());
+ }
+
+ public void testUnknownExtensions() throws Exception {
+ // Make sure fields are properly parsed to the UnknownFieldSet even when
+ // they are declared as extension numbers.
+
+ TestEmptyMessageWithExtensions message =
+ TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
+
+ assertEquals(unknownFields.asMap().size(),
+ message.getUnknownFields().asMap().size());
+ assertEquals(allFieldsData, message.toByteString());
+ }
+
+ public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing extensions.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllExtensions allExtensionsMessage =
+ TestAllExtensions.parseFrom(bizarroData);
+ TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the debug strings
+ // should be the same.
+ assertEquals(emptyMessage.toString(),
+ allExtensionsMessage.toString());
+ }
+
+ public void testParseUnknownEnumValue() throws Exception {
+ Descriptors.FieldDescriptor singularField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+ Descriptors.FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+ assertNotNull(singularField);
+ assertNotNull(repeatedField);
+
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(singularField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+ .addVarint(5) // not valid
+ .build())
+ .addField(repeatedField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+ .addVarint(4) // not valid
+ .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+ .addVarint(6) // not valid
+ .build())
+ .build()
+ .toByteString();
+
+ {
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getOptionalNestedEnum());
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getRepeatedNestedEnumList());
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+
+ {
+ TestAllExtensions message =
+ TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension));
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java
new file mode 100644
index 00000000..84cc89f8
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -0,0 +1,226 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+
+/**
+ * Tests related to parsing and serialization.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class WireFormatTest extends TestCase {
+ public void testSerialization() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ public void testSerializeExtensions() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serealize a TestAllExtensions then parse it as TestAllTypes
+ // it should work.
+
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ public void testParseExtensions() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serealize a TestAllTypes then parse it as TestAllExtensions
+ // it should work.
+
+ TestAllTypes message = TestUtil.getAllSet();
+ ByteString rawBytes = message.toByteString();
+
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ TestUtil.registerAllExtensions(registry);
+ registry = registry.getUnmodifiable();
+
+ TestAllExtensions message2 =
+ TestAllExtensions.parseFrom(rawBytes, registry);
+
+ TestUtil.assertAllExtensionsSet(message2);
+ }
+
+ public void testExtensionsSerializedSize() throws Exception {
+ assertEquals(TestUtil.getAllSet().getSerializedSize(),
+ TestUtil.getAllExtensionsSet().getSerializedSize());
+ }
+
+ private void assertFieldsInOrder(ByteString data) throws Exception {
+ CodedInputStream input = data.newCodedInput();
+ int previousTag = 0;
+
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ assertTrue(tag > previousTag);
+ input.skipField(tag);
+ }
+ }
+
+ public void testInterleavedFieldsAndExtensions() throws Exception {
+ // Tests that fields are written in order even when extension ranges
+ // are interleaved with field numbers.
+ ByteString data =
+ TestFieldOrderings.newBuilder()
+ .setMyInt(1)
+ .setMyString("foo")
+ .setMyFloat(1.0F)
+ .setExtension(UnittestProto.myExtensionInt, 23)
+ .setExtension(UnittestProto.myExtensionString, "bar")
+ .build().toByteString();
+ assertFieldsInOrder(data);
+
+ Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+ ByteString dynamic_data =
+ DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+ .setField(descriptor.findFieldByName("my_int"), 1L)
+ .setField(descriptor.findFieldByName("my_string"), "foo")
+ .setField(descriptor.findFieldByName("my_float"), 1.0F)
+ .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+ .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+ .build().toByteString();
+ assertFieldsInOrder(dynamic_data);
+ }
+
+ private static final int UNKNOWN_TYPE_ID = 1550055;
+ private static final int TYPE_ID_1 =
+ TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
+ private static final int TYPE_ID_2 =
+ TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
+
+ public void testSerializeMessageSet() throws Exception {
+ // Set up a TestMessageSet with two known messages and an unknown one.
+ TestMessageSet messageSet =
+ TestMessageSet.newBuilder()
+ .setExtension(
+ TestMessageSetExtension1.messageSetExtension,
+ TestMessageSetExtension1.newBuilder().setI(123).build())
+ .setExtension(
+ TestMessageSetExtension2.messageSetExtension,
+ TestMessageSetExtension2.newBuilder().setStr("foo").build())
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(UNKNOWN_TYPE_ID,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(ByteString.copyFromUtf8("bar"))
+ .build())
+ .build())
+ .build();
+
+ ByteString data = messageSet.toByteString();
+
+ // Parse back using RawMessageSet and check the contents.
+ RawMessageSet raw = RawMessageSet.parseFrom(data);
+
+ assertTrue(raw.getUnknownFields().asMap().isEmpty());
+
+ assertEquals(3, raw.getItemCount());
+ assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
+ assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
+ assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
+
+ TestMessageSetExtension1 message1 =
+ TestMessageSetExtension1.parseFrom(
+ raw.getItem(0).getMessage().toByteArray());
+ assertEquals(123, message1.getI());
+
+ TestMessageSetExtension2 message2 =
+ TestMessageSetExtension2.parseFrom(
+ raw.getItem(1).getMessage().toByteArray());
+ assertEquals("foo", message2.getStr());
+
+ assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+ }
+
+ public void testParseMessageSet() throws Exception {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+ extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+ // Set up a RawMessageSet with two known messages and an unknown one.
+ RawMessageSet raw =
+ RawMessageSet.newBuilder()
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_1)
+ .setMessage(
+ TestMessageSetExtension1.newBuilder()
+ .setI(123)
+ .build().toByteString())
+ .build())
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_2)
+ .setMessage(
+ TestMessageSetExtension2.newBuilder()
+ .setStr("foo")
+ .build().toByteString())
+ .build())
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(UNKNOWN_TYPE_ID)
+ .setMessage(ByteString.copyFromUtf8("bar"))
+ .build())
+ .build();
+
+ ByteString data = raw.toByteString();
+
+ // Parse as a TestMessageSet and check the contents.
+ TestMessageSet messageSet =
+ TestMessageSet.parseFrom(data, extensionRegistry);
+
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ assertEquals("foo", messageSet.getExtension(
+ TestMessageSetExtension2.messageSetExtension).getStr());
+
+ // Check for unknown field with type LENGTH_DELIMITED,
+ // number UNKNOWN_TYPE_ID, and contents "bar".
+ UnknownFieldSet unknownFields = messageSet.getUnknownFields();
+ assertEquals(1, unknownFields.asMap().size());
+ assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
+
+ UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
+ assertEquals(1, field.getLengthDelimitedList().size());
+ assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
+ }
+}
+
diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/src/test/java/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 00000000..1dbadfe0
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/multiple_files_test.proto
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+ message NestedMessage {
+ optional int32 i = 1;
+ }
+ enum NestedEnum {
+ BAZ = 3;
+ }
+ optional NestedMessage nested = 1;
+ repeated TestAllTypes foreign = 2;
+ optional NestedEnum nested_enum = 3;
+ optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+ FOO = 1;
+ BAR = 2;
+}
+
+service ServiceWithNoOuter {
+ rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+ optional int32 extension_with_outer = 1234567;
+}
diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4
new file mode 100644
index 00000000..2cf20de1
--- /dev/null
+++ b/m4/acx_pthread.m4
@@ -0,0 +1,363 @@
+# This was retrieved from
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi
+# See also (perhaps for new versions?)
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi
+#
+# We've rewritten the inconsistency check code (from avahi), to work
+# more broadly. In particular, it no longer assumes ld accepts -zdefs.
+# This caused a restructing of the code, but the functionality has only
+# changed a little.
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl LIBS="$PTHREAD_LIBS $LIBS"
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+dnl
+dnl Checks for GCC shared/pthread inconsistency based on work by
+dnl Marcin Owsiany <marcin@owsiany.pl>
+
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+
+ # The next part tries to detect GCC inconsistency with -shared on some
+ # architectures and systems. The problem is that in certain
+ # configurations, when -shared is specified, GCC "forgets" to
+ # internally use various flags which are still necessary.
+
+ #
+ # Prepare the flags
+ #
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ save_CC="$CC"
+
+ # Try with the flags determined by the earlier checks.
+ #
+ # -Wl,-z,defs forces link-time symbol resolution, so that the
+ # linking checks with -shared actually have any value
+ #
+ # FIXME: -fPIC is required for -shared on many architectures,
+ # so we specify it here, but the right way would probably be to
+ # properly detect whether it is actually required.
+ CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CC="$PTHREAD_CC"
+
+ # In order not to create several levels of indentation, we test
+ # the value of "$done" until we find the cure or run out of ideas.
+ done="no"
+
+ # First, make sure the CFLAGS we added are actually accepted by our
+ # compiler. If not (and OS X's ld, for instance, does not accept -z),
+ # then we can't do this test.
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
+ AC_TRY_LINK(,, , [done=yes])
+
+ if test "x$done" = xyes ; then
+ AC_MSG_RESULT([no])
+ else
+ AC_MSG_RESULT([yes])
+ fi
+ fi
+
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -pthread is sufficient with -shared])
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ #
+ # Linux gcc on some architectures such as mips/mipsel forgets
+ # about -lpthread
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lpthread fixes that])
+ LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ #
+ # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lc_r fixes that])
+ LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ if test x"$done" = xno; then
+ # OK, we have run out of ideas
+ AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries])
+
+ # so it's not safe to assume that we may use pthreads
+ acx_pthread_ok=no
+ fi
+
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ CC="$save_CC"
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/m4/stl_hash.m4 b/m4/stl_hash.m4
new file mode 100644
index 00000000..912b954e
--- /dev/null
+++ b/m4/stl_hash.m4
@@ -0,0 +1,43 @@
+# We check two things: where the include file is for hash_map, and
+# what namespace hash_map lives in within that include file. We
+# include AC_TRY_COMPILE for all the combinations we've seen in the
+# wild. We define one of HAVE_HASH_MAP or HAVE_EXT_HASH_MAP depending
+# on location, and HASH_NAMESPACE to be the namespace hash_map is
+# defined in.
+#
+# Ideally we'd use AC_CACHE_CHECK, but that only lets us store one value
+# at a time, and we need to store two (filename and namespace).
+# prints messages itself, so we have to do the message-printing ourselves
+# via AC_MSG_CHECKING + AC_MSG_RESULT. (TODO(csilvers): can we cache?)
+
+AC_DEFUN([AC_CXX_STL_HASH],
+ [AC_MSG_CHECKING(the location of hash_map)
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ ac_cv_cxx_hash_map=""
+ for location in ext/hash_map hash_map; do
+ for namespace in __gnu_cxx "" std stdext; do
+ if test -z "$ac_cv_cxx_hash_map"; then
+ AC_TRY_COMPILE([#include <$location>],
+ [${namespace}::hash_map<int, int> t],
+ [ac_cv_cxx_hash_map="<$location>";
+ ac_cv_cxx_hash_namespace="$namespace";])
+ fi
+ done
+ done
+ ac_cv_cxx_hash_set=`echo "$ac_cv_cxx_hash_map" | sed s/map/set/`;
+ if test -n "$ac_cv_cxx_hash_map"; then
+ AC_DEFINE(HAVE_HASH_MAP, 1, [define if the compiler has hash_map])
+ AC_DEFINE(HAVE_HASH_SET, 1, [define if the compiler has hash_set])
+ AC_DEFINE_UNQUOTED(HASH_MAP_H,$ac_cv_cxx_hash_map,
+ [the location of <hash_map>])
+ AC_DEFINE_UNQUOTED(HASH_SET_H,$ac_cv_cxx_hash_set,
+ [the location of <hash_set>])
+ AC_DEFINE_UNQUOTED(HASH_NAMESPACE,$ac_cv_cxx_hash_namespace,
+ [the namespace of hash_map/hash_set])
+ AC_MSG_RESULT([$ac_cv_cxx_hash_map])
+ else
+ AC_MSG_RESULT()
+ AC_MSG_WARN([could not find an STL hash_map])
+ fi
+])
diff --git a/python/README.txt b/python/README.txt
new file mode 100644
index 00000000..44bbee0b
--- /dev/null
+++ b/python/README.txt
@@ -0,0 +1,53 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+
+This directory contains the Python Protocol Buffers runtime library.
+
+Installation
+============
+
+1) Make sure you have Python 2.4 or newer. If in doubt, run:
+
+ $ python -V
+
+2) If you do not have setuptools installed, note that it will be
+ downloaded and installed automatically as soon as you run setup.py.
+ If you would rather install it manually, you may do so by following
+ the instructions on this page:
+
+ http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions
+
+3) Build the C++ code, or install a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+4) Run the tests:
+
+ $ python setup.py test
+
+ If some tests fail, this library may not work correctly on your
+ system. Continue at your own risk.
+
+ Please note that there is a known problem with some versions of
+ Python on Cygwin which causes the tests to fail after printing the
+ error: "sem_init: Resource temporarily unavailable". This appears
+ to be a bug either in Cygwin or in Python:
+ http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html
+ We do not know if or when it might me fixed. We also do not know
+ how likely it is that this bug will affect users in practice.
+
+5) Install:
+
+ $ python setup.py install
+
+ This step may require superuser privileges.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ http://code.google.com/apis/protocolbuffers/
diff --git a/python/ez_setup.py b/python/ez_setup.py
new file mode 100755
index 00000000..989d366c
--- /dev/null
+++ b/python/ez_setup.py
@@ -0,0 +1,277 @@
+#!python
+
+# This file was obtained from:
+# http://peak.telecommunity.com/dist/ez_setup.py
+# on 2008/7/1.
+
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c8"
+DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+ 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+ 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+ 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+ 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+ 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+ 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+ 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+ 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+ 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+ 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+ 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+ 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+ 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+ 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+ 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+ 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+ 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+ 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+ 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+ 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+}
+
+import sys, os
+
+def _validate_md5(egg_name, data):
+ if egg_name in md5_data:
+ from md5 import md5
+ digest = md5(data).hexdigest()
+ if digest != md5_data[egg_name]:
+ print >>sys.stderr, (
+ "md5 validation of %s failed! (Possible download problem?)"
+ % egg_name
+ )
+ sys.exit(2)
+ return data
+
+
+def use_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ download_delay=15
+):
+ """Automatically find/download setuptools and make it available on sys.path
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end with
+ a '/'). `to_dir` is the directory where setuptools will be downloaded, if
+ it is not already available. If `download_delay` is specified, it should
+ be the number of seconds that will be paused before initiating a download,
+ should one be required. If an older version of setuptools is installed,
+ this routine will print a message to ``sys.stderr`` and raise SystemExit in
+ an attempt to abort the calling script.
+ """
+ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+ def do_download():
+ egg = download_setuptools(version, download_base, to_dir, download_delay)
+ sys.path.insert(0, egg)
+ import setuptools; setuptools.bootstrap_install_from = egg
+ try:
+ import pkg_resources
+ except ImportError:
+ return do_download()
+ try:
+ pkg_resources.require("setuptools>="+version); return
+ except pkg_resources.VersionConflict, e:
+ if was_imported:
+ print >>sys.stderr, (
+ "The required version of setuptools (>=%s) is not available, and\n"
+ "can't be installed while this script is running. Please install\n"
+ " a more recent version first, using 'easy_install -U setuptools'."
+ "\n\n(Currently using %r)"
+ ) % (version, e.args[0])
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return do_download()
+ except pkg_resources.DistributionNotFound:
+ return do_download()
+
+def download_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ delay = 15
+):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download attempt.
+ """
+ import urllib2, shutil
+ egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+ url = download_base + egg_name
+ saveto = os.path.join(to_dir, egg_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ from distutils import log
+ if delay:
+ log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help). I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+ version, download_base, delay, url
+ ); from time import sleep; sleep(delay)
+ log.warn("Downloading %s", url)
+ src = urllib2.urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = _validate_md5(egg_name, src.read())
+ dst = open(saveto,"wb"); dst.write(data)
+ finally:
+ if src: src.close()
+ if dst: dst.close()
+ return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ try:
+ import setuptools
+ except ImportError:
+ egg = None
+ try:
+ egg = download_setuptools(version, delay=0)
+ sys.path.insert(0,egg)
+ from setuptools.command.easy_install import main
+ return main(list(argv)+[egg]) # we're done here
+ finally:
+ if egg and os.path.exists(egg):
+ os.unlink(egg)
+ else:
+ if setuptools.__version__ == '0.0.1':
+ print >>sys.stderr, (
+ "You have an obsolete version of setuptools installed. Please\n"
+ "remove it from your system entirely before rerunning this script."
+ )
+ sys.exit(2)
+
+ req = "setuptools>="+version
+ import pkg_resources
+ try:
+ pkg_resources.require(req)
+ except pkg_resources.VersionConflict:
+ try:
+ from setuptools.command.easy_install import main
+ except ImportError:
+ from easy_install import main
+ main(list(argv)+[download_setuptools(delay=0)])
+ sys.exit(0) # try to force an exit
+ else:
+ if argv:
+ from setuptools.command.easy_install import main
+ main(argv)
+ else:
+ print "Setuptools version",version,"or greater has been installed."
+ print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+ """Update our built-in md5 registry"""
+
+ import re
+ from md5 import md5
+
+ for name in filenames:
+ base = os.path.basename(name)
+ f = open(name,'rb')
+ md5_data[base] = md5(f.read()).hexdigest()
+ f.close()
+
+ data = [" %r: %r,\n" % it for it in md5_data.items()]
+ data.sort()
+ repl = "".join(data)
+
+ import inspect
+ srcfile = inspect.getsourcefile(sys.modules[__name__])
+ f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+ match = re.search("\nmd5_data = {\n([^}]+)}", src)
+ if not match:
+ print >>sys.stderr, "Internal error!"
+ sys.exit(2)
+
+ src = src[:match.start(1)] + repl + src[match.end(1):]
+ f = open(srcfile,'w')
+ f.write(src)
+ f.close()
+
+
+if __name__=='__main__':
+ if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+ update_md5(sys.argv[2:])
+ else:
+ main(sys.argv[1:])
+
+
+
+
+
diff --git a/python/google/__init__.py b/python/google/__init__.py
new file mode 100755
index 00000000..de40ea7c
--- /dev/null
+++ b/python/google/__init__.py
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/python/google/protobuf/__init__.py
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
new file mode 100755
index 00000000..04748053
--- /dev/null
+++ b/python/google/protobuf/descriptor.py
@@ -0,0 +1,419 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+# TODO(robinson): We probably need to provide deep-copy methods for
+# descriptor types. When a FieldDescriptor is passed into
+# Descriptor.__init__(), we should make a deep copy and then set
+# containing_type on it. Alternatively, we could just get
+# rid of containing_type (iit's not needed for reflection.py, at least).
+#
+# TODO(robinson): Print method?
+#
+# TODO(robinson): Useful __repr__?
+
+"""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)'
+
+class DescriptorBase(object):
+
+ """Descriptors base class.
+
+ This class is the base of all descriptor classes. It provides common options
+ related functionaility.
+ """
+
+ def __init__(self, options, options_class_name):
+ """Initialize the descriptor given its options message and the name of the
+ class of the options message. The name of the class is required in case
+ the options message is None and has to be created.
+ """
+ self._options = options
+ self._options_class_name = options_class_name
+
+ 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))
+ self._options = options_class()
+ return self._options
+
+
+class Descriptor(DescriptorBase):
+
+ """Descriptor for a protocol message type.
+
+ A Descriptor instance has the following 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.
+
+ filename: (str) Name of the .proto file containing this message.
+
+ containing_type: (Descriptor) Reference to the descriptor of the
+ type containing us, or None if we have no containing type.
+
+ fields: (list of FieldDescriptors) Field descriptors for all
+ fields in this type.
+ fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor
+ objects as in |fields|, but indexed by "number" attribute in each
+ FieldDescriptor.
+ fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
+ objects as in |fields|, but indexed by "name" attribute in each
+ FieldDescriptor.
+
+ nested_types: (list of Descriptors) Descriptor references
+ for all protocol message types nested within this one.
+ nested_types_by_name: (dict str -> Descriptor) Same Descriptor
+ objects as in |nested_types|, but indexed by "name" attribute
+ in each Descriptor.
+
+ enum_types: (list of EnumDescriptors) EnumDescriptor references
+ for all enums contained within this type.
+ enum_types_by_name: (dict str ->EnumDescriptor) Same EnumDescriptor
+ objects as in |enum_types|, but indexed by "name" attribute
+ in each EnumDescriptor.
+ enum_values_by_name: (dict str -> EnumValueDescriptor) Dict mapping
+ from enum value name to EnumValueDescriptor for that value.
+
+ extensions: (list of FieldDescriptor) All extensions defined directly
+ within this message type (NOT within a nested type).
+ extensions_by_name: (dict, string -> FieldDescriptor) Same FieldDescriptor
+ objects as |extensions|, but indexed by "name" attribute of each
+ FieldDescriptor.
+
+ options: (descriptor_pb2.MessageOptions) Protocol message options or None
+ to use default message options.
+ """
+
+ def __init__(self, name, full_name, filename, containing_type,
+ fields, nested_types, enum_types, extensions, options=None):
+ """Arguments to __init__() are as described in the description
+ of Descriptor fields above.
+ """
+ super(Descriptor, self).__init__(options, 'MessageOptions')
+ self.name = name
+ self.full_name = full_name
+ self.filename = filename
+ self.containing_type = containing_type
+
+ # 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.nested_types = nested_types
+ 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)
+
+
+# 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.
+
+ A FieldDescriptor instance has the following attriubtes:
+
+ 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: (One of the TYPE_* constants below) Declared type.
+ cpp_type: (One of the CPPTYPE_* constants below) C++ type used to
+ represent this field.
+
+ label: (One of the LABEL_* constants below) Tells whether this
+ field is optional, required, or repeated.
+ 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.
+ """
+
+ # 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
+
+ # 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
+
+ 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):
+ """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.
+ """
+ super(FieldDescriptor, self).__init__(options, 'FieldOptions')
+ self.name = name
+ self.full_name = full_name
+ self.index = index
+ self.number = number
+ self.type = type
+ self.cpp_type = cpp_type
+ self.label = label
+ 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
+
+
+class EnumDescriptor(DescriptorBase):
+
+ """Descriptor for an enum defined in a .proto file.
+
+ An EnumDescriptor instance has the following attributes:
+
+ name: (str) Name of the enum type.
+ full_name: (str) Full name of the type, including package name
+ and any enclosing type(s).
+ filename: (str) Name of the .proto file in which this appears.
+
+ values: (list of EnumValueDescriptors) List of the values
+ in this enum.
+ values_by_name: (dict str -> EnumValueDescriptor) Same as |values|,
+ but indexed by the "name" field of each EnumValueDescriptor.
+ values_by_number: (dict int -> EnumValueDescriptor) Same as |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.
+ options: (descriptor_pb2.EnumOptions) Enum options message or
+ None to use default enum options.
+ """
+
+ def __init__(self, name, full_name, filename, values,
+ containing_type=None, options=None):
+ """Arguments are as described in the attribute description above."""
+ super(EnumDescriptor, self).__init__(options, 'EnumOptions')
+ self.name = name
+ self.full_name = full_name
+ self.filename = filename
+ self.values = values
+ for value in self.values:
+ value.type = self
+ self.values_by_name = dict((v.name, v) for v in values)
+ self.values_by_number = dict((v.number, v) for v in values)
+ self.containing_type = containing_type
+
+
+class EnumValueDescriptor(DescriptorBase):
+
+ """Descriptor for a single value within an enum.
+
+ 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) EnumDescriptor to which this value
+ belongs. Set by 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.
+ """
+
+ def __init__(self, name, index, number, type=None, options=None):
+ """Arguments are as described in the attribute description above."""
+ super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions')
+ self.name = name
+ self.index = index
+ self.number = number
+ self.type = type
+
+
+class ServiceDescriptor(DescriptorBase):
+
+ """Descriptor for a service.
+
+ 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 withing the .proto file.
+ methods: (list of MethodDescriptor) List of methods provided by this
+ service.
+ options: (descriptor_pb2.ServiceOptions) Service options message or
+ None to use default service options.
+ """
+
+ def __init__(self, name, full_name, index, methods, options=None):
+ super(ServiceDescriptor, self).__init__(options, 'ServiceOptions')
+ self.name = name
+ self.full_name = full_name
+ self.index = index
+ self.methods = 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."""
+ for method in self.methods:
+ if name == method.name:
+ return method
+ return None
+
+
+class MethodDescriptor(DescriptorBase):
+
+ """Descriptor for a method in a service.
+
+ 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: The descriptor of the message that this method accepts.
+ output_type: The descriptor of the message that this method returns.
+ options: (descriptor_pb2.MethodOptions) Method options message or
+ None to use default method options.
+ """
+
+ def __init__(self, name, full_name, index, containing_service,
+ input_type, output_type, options=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.
+ """
+ super(MethodDescriptor, self).__init__(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
+
+
+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;
diff --git a/python/google/protobuf/internal/__init__.py b/python/google/protobuf/internal/__init__.py
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/python/google/protobuf/internal/__init__.py
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
new file mode 100755
index 00000000..b81f04a5
--- /dev/null
+++ b/python/google/protobuf/internal/decoder.py
@@ -0,0 +1,194 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Class for decoding protocol buffer primitives.
+
+Contains the logic for decoding every logical protocol field type
+from one of the 5 physical wire types.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+from google.protobuf import message
+from google.protobuf.internal import input_stream
+from google.protobuf.internal import wire_format
+
+
+
+# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
+# that the interface is strongly inspired by WireFormat from the C++ proto2
+# implementation.
+
+
+class Decoder(object):
+
+ """Decodes logical protocol buffer fields from the wire."""
+
+ def __init__(self, s):
+ """Initializes the decoder to read from s.
+
+ Args:
+ s: An immutable sequence of bytes, which must be accessible
+ via the Python buffer() primitive (i.e., buffer(s)).
+ """
+ self._stream = input_stream.InputStream(s)
+
+ def EndOfStream(self):
+ """Returns true iff we've reached the end of the bytes we're reading."""
+ return self._stream.EndOfStream()
+
+ def Position(self):
+ """Returns the 0-indexed position in |s|."""
+ return self._stream.Position()
+
+ def ReadFieldNumberAndWireType(self):
+ """Reads a tag from the wire. Returns a (field_number, wire_type) pair."""
+ tag_and_type = self.ReadUInt32()
+ return wire_format.UnpackTag(tag_and_type)
+
+ def SkipBytes(self, bytes):
+ """Skips the specified number of bytes on the wire."""
+ self._stream.SkipBytes(bytes)
+
+ # Note that the Read*() methods below are not exactly symmetrical with the
+ # corresponding Encoder.Append*() methods. Those Encoder methods first
+ # encode a tag, but the Read*() methods below assume that the tag has already
+ # been read, and that the client wishes to read a field of the specified type
+ # starting at the current position.
+
+ def ReadInt32(self):
+ """Reads and returns a signed, varint-encoded, 32-bit integer."""
+ return self._stream.ReadVarint32()
+
+ def ReadInt64(self):
+ """Reads and returns a signed, varint-encoded, 64-bit integer."""
+ return self._stream.ReadVarint64()
+
+ def ReadUInt32(self):
+ """Reads and returns an signed, varint-encoded, 32-bit integer."""
+ return self._stream.ReadVarUInt32()
+
+ def ReadUInt64(self):
+ """Reads and returns an signed, varint-encoded,64-bit integer."""
+ return self._stream.ReadVarUInt64()
+
+ def ReadSInt32(self):
+ """Reads and returns a signed, zigzag-encoded, varint-encoded,
+ 32-bit integer."""
+ return wire_format.ZigZagDecode(self._stream.ReadVarUInt32())
+
+ def ReadSInt64(self):
+ """Reads and returns a signed, zigzag-encoded, varint-encoded,
+ 64-bit integer."""
+ return wire_format.ZigZagDecode(self._stream.ReadVarUInt64())
+
+ def ReadFixed32(self):
+ """Reads and returns an unsigned, fixed-width, 32-bit integer."""
+ return self._stream.ReadLittleEndian32()
+
+ def ReadFixed64(self):
+ """Reads and returns an unsigned, fixed-width, 64-bit integer."""
+ return self._stream.ReadLittleEndian64()
+
+ def ReadSFixed32(self):
+ """Reads and returns a signed, fixed-width, 32-bit integer."""
+ value = self._stream.ReadLittleEndian32()
+ if value >= (1 << 31):
+ value -= (1 << 32)
+ return value
+
+ def ReadSFixed64(self):
+ """Reads and returns a signed, fixed-width, 64-bit integer."""
+ value = self._stream.ReadLittleEndian64()
+ if value >= (1 << 63):
+ value -= (1 << 64)
+ return value
+
+ def ReadFloat(self):
+ """Reads and returns a 4-byte floating-point number."""
+ serialized = self._stream.ReadString(4)
+ return struct.unpack('f', serialized)[0]
+
+ def ReadDouble(self):
+ """Reads and returns an 8-byte floating-point number."""
+ serialized = self._stream.ReadString(8)
+ return struct.unpack('d', serialized)[0]
+
+ def ReadBool(self):
+ """Reads and returns a bool."""
+ i = self._stream.ReadVarUInt32()
+ return bool(i)
+
+ def ReadEnum(self):
+ """Reads and returns an enum value."""
+ return self._stream.ReadVarUInt32()
+
+ def ReadString(self):
+ """Reads and returns a length-delimited string."""
+ length = self._stream.ReadVarUInt32()
+ return self._stream.ReadString(length)
+
+ def ReadBytes(self):
+ """Reads and returns a length-delimited byte sequence."""
+ return self.ReadString()
+
+ def ReadMessageInto(self, msg):
+ """Calls msg.MergeFromString() to merge
+ length-delimited serialized message data into |msg|.
+
+ REQUIRES: The decoder must be positioned at the serialized "length"
+ prefix to a length-delmiited serialized message.
+
+ POSTCONDITION: The decoder is positioned just after the
+ serialized message, and we have merged those serialized
+ contents into |msg|.
+ """
+ length = self._stream.ReadVarUInt32()
+ sub_buffer = self._stream.GetSubBuffer(length)
+ num_bytes_used = msg.MergeFromString(sub_buffer)
+ if num_bytes_used != length:
+ raise message.DecodeError(
+ 'Submessage told to deserialize from %d-byte encoding, '
+ 'but used only %d bytes' % (length, num_bytes_used))
+ self._stream.SkipBytes(num_bytes_used)
+
+ def ReadGroupInto(self, expected_field_number, group):
+ """Calls group.MergeFromString() to merge
+ END_GROUP-delimited serialized message data into |group|.
+ We'll raise an exception if we don't find an END_GROUP
+ tag immediately after the serialized message contents.
+
+ REQUIRES: The decoder is positioned just after the START_GROUP
+ tag for this group.
+
+ POSTCONDITION: The decoder is positioned just after the
+ END_GROUP tag for this group, and we have merged
+ the contents of the group into |group|.
+ """
+ sub_buffer = self._stream.GetSubBuffer() # No a priori length limit.
+ num_bytes_used = group.MergeFromString(sub_buffer)
+ if num_bytes_used < 0:
+ raise message.DecodeError('Group message reported negative bytes read.')
+ self._stream.SkipBytes(num_bytes_used)
+ field_number, field_type = self.ReadFieldNumberAndWireType()
+ if field_type != wire_format.WIRETYPE_END_GROUP:
+ raise message.DecodeError('Group message did not end with an END_GROUP.')
+ if field_number != expected_field_number:
+ raise message.DecodeError('END_GROUP tag had field '
+ 'number %d, was expecting field number %d' % (
+ field_number, expected_field_number))
+ # We're now positioned just after the END_GROUP tag. Perfect.
diff --git a/python/google/protobuf/internal/decoder_test.py b/python/google/protobuf/internal/decoder_test.py
new file mode 100755
index 00000000..e36a96fc
--- /dev/null
+++ b/python/google/protobuf/internal/decoder_test.py
@@ -0,0 +1,230 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Test for google.protobuf.internal.decoder."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+import unittest
+from google.protobuf.internal import wire_format
+from google.protobuf.internal import encoder
+from google.protobuf.internal import decoder
+import logging
+import mox
+from google.protobuf.internal import input_stream
+from google.protobuf import message
+
+
+class DecoderTest(unittest.TestCase):
+
+ def setUp(self):
+ self.mox = mox.Mox()
+ self.mock_stream = self.mox.CreateMock(input_stream.InputStream)
+ self.mock_message = self.mox.CreateMock(message.Message)
+
+ def testReadFieldNumberAndWireType(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.
+ e = encoder.Encoder()
+ e._AppendTag(expected_field_number, expected_wire_type)
+ s = e.ToString()
+ d = decoder.Decoder(s)
+ field_number, wire_type = d.ReadFieldNumberAndWireType()
+ self.assertEqual(expected_field_number, field_number)
+ self.assertEqual(expected_wire_type, wire_type)
+
+ def ReadScalarTestHelper(self, test_name, decoder_method, expected_result,
+ expected_stream_method_name,
+ stream_method_return, *args):
+ """Helper for testReadScalars below.
+
+ Calls one of the Decoder.Read*() methods and ensures that the results are
+ as expected.
+
+ Args:
+ test_name: Name of this test, used for logging only.
+ decoder_method: Unbound decoder.Decoder method to call.
+ expected_result: Value we expect returned from decoder_method().
+ expected_stream_method_name: (string) Name of the InputStream
+ method we expect Decoder to call to actually read the value
+ on the wire.
+ stream_method_return: Value our mocked-out stream method should
+ return to the decoder.
+ args: Additional arguments that we expect to be passed to the
+ stream method.
+ """
+ logging.info('Testing %s scalar input.\n'
+ 'Calling %r(), and expecting that to call the '
+ 'stream method %s(%r), which will return %r. Finally, '
+ 'expecting the Decoder method to return %r'% (
+ test_name, decoder_method,
+ expected_stream_method_name, args, stream_method_return,
+ expected_result))
+
+ d = decoder.Decoder('')
+ d._stream = self.mock_stream
+ if decoder_method in (decoder.Decoder.ReadString,
+ decoder.Decoder.ReadBytes):
+ self.mock_stream.ReadVarUInt32().AndReturn(len(stream_method_return))
+ # We have to use names instead of methods to work around some
+ # mox weirdness. (ResetAll() is overzealous).
+ expected_stream_method = getattr(self.mock_stream,
+ expected_stream_method_name)
+ expected_stream_method(*args).AndReturn(stream_method_return)
+
+ self.mox.ReplayAll()
+ self.assertEqual(expected_result, decoder_method(d))
+ self.mox.VerifyAll()
+ self.mox.ResetAll()
+
+ def testReadScalars(self):
+ test_string = 'I can feel myself getting sutpider.'
+ scalar_tests = [
+ ['int32', decoder.Decoder.ReadInt32, 0, 'ReadVarint32', 0],
+ ['int64', decoder.Decoder.ReadInt64, 0, 'ReadVarint64', 0],
+ ['uint32', decoder.Decoder.ReadUInt32, 0, 'ReadVarUInt32', 0],
+ ['uint64', decoder.Decoder.ReadUInt64, 0, 'ReadVarUInt64', 0],
+ ['fixed32', decoder.Decoder.ReadFixed32, 0xffffffff,
+ 'ReadLittleEndian32', 0xffffffff],
+ ['fixed64', decoder.Decoder.ReadFixed64, 0xffffffffffffffff,
+ 'ReadLittleEndian64', 0xffffffffffffffff],
+ ['sfixed32', decoder.Decoder.ReadSFixed32, -1,
+ 'ReadLittleEndian32', 0xffffffff],
+ ['sfixed64', decoder.Decoder.ReadSFixed64, -1,
+ 'ReadLittleEndian64', 0xffffffffffffffff],
+ ['float', decoder.Decoder.ReadFloat, 0.0,
+ 'ReadString', struct.pack('f', 0.0), 4],
+ ['double', decoder.Decoder.ReadDouble, 0.0,
+ 'ReadString', struct.pack('d', 0.0), 8],
+ ['bool', decoder.Decoder.ReadBool, True, 'ReadVarUInt32', 1],
+ ['enum', decoder.Decoder.ReadEnum, 23, 'ReadVarUInt32', 23],
+ ['string', decoder.Decoder.ReadString,
+ test_string, 'ReadString', test_string, len(test_string)],
+ ['bytes', decoder.Decoder.ReadBytes,
+ test_string, 'ReadString', test_string, len(test_string)],
+ # We test zigzag decoding routines more extensively below.
+ ['sint32', decoder.Decoder.ReadSInt32, -1, 'ReadVarUInt32', 1],
+ ['sint64', decoder.Decoder.ReadSInt64, -1, 'ReadVarUInt64', 1],
+ ]
+ # Ensure that we're testing different Decoder methods and using
+ # different test names in all test cases above.
+ self.assertEqual(len(scalar_tests), len(set(t[0] for t in scalar_tests)))
+ self.assertEqual(len(scalar_tests), len(set(t[1] for t in scalar_tests)))
+ for args in scalar_tests:
+ self.ReadScalarTestHelper(*args)
+
+ def testReadMessageInto(self):
+ length = 23
+ def Test(simulate_error):
+ d = decoder.Decoder('')
+ d._stream = self.mock_stream
+ self.mock_stream.ReadVarUInt32().AndReturn(length)
+ sub_buffer = object()
+ self.mock_stream.GetSubBuffer(length).AndReturn(sub_buffer)
+
+ if simulate_error:
+ self.mock_message.MergeFromString(sub_buffer).AndReturn(length - 1)
+ self.mox.ReplayAll()
+ self.assertRaises(
+ message.DecodeError, d.ReadMessageInto, self.mock_message)
+ else:
+ self.mock_message.MergeFromString(sub_buffer).AndReturn(length)
+ self.mock_stream.SkipBytes(length)
+ self.mox.ReplayAll()
+ d.ReadMessageInto(self.mock_message)
+
+ self.mox.VerifyAll()
+ self.mox.ResetAll()
+
+ Test(simulate_error=False)
+ Test(simulate_error=True)
+
+ def testReadGroupInto_Success(self):
+ # Test both the empty and nonempty cases.
+ for num_bytes in (5, 0):
+ field_number = expected_field_number = 10
+ d = decoder.Decoder('')
+ d._stream = self.mock_stream
+ sub_buffer = object()
+ self.mock_stream.GetSubBuffer().AndReturn(sub_buffer)
+ self.mock_message.MergeFromString(sub_buffer).AndReturn(num_bytes)
+ self.mock_stream.SkipBytes(num_bytes)
+ self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
+ field_number, wire_format.WIRETYPE_END_GROUP))
+ self.mox.ReplayAll()
+ d.ReadGroupInto(expected_field_number, self.mock_message)
+ self.mox.VerifyAll()
+ self.mox.ResetAll()
+
+ def ReadGroupInto_FailureTestHelper(self, bytes_read):
+ d = decoder.Decoder('')
+ d._stream = self.mock_stream
+ sub_buffer = object()
+ self.mock_stream.GetSubBuffer().AndReturn(sub_buffer)
+ self.mock_message.MergeFromString(sub_buffer).AndReturn(bytes_read)
+ return d
+
+ def testReadGroupInto_NegativeBytesReported(self):
+ expected_field_number = 10
+ d = self.ReadGroupInto_FailureTestHelper(bytes_read=-1)
+ self.mox.ReplayAll()
+ self.assertRaises(message.DecodeError,
+ d.ReadGroupInto, expected_field_number,
+ self.mock_message)
+ self.mox.VerifyAll()
+
+ def testReadGroupInto_NoEndGroupTag(self):
+ field_number = expected_field_number = 10
+ num_bytes = 5
+ d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes)
+ self.mock_stream.SkipBytes(num_bytes)
+ # Right field number, wrong wire type.
+ self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
+ field_number, wire_format.WIRETYPE_LENGTH_DELIMITED))
+ self.mox.ReplayAll()
+ self.assertRaises(message.DecodeError,
+ d.ReadGroupInto, expected_field_number,
+ self.mock_message)
+ self.mox.VerifyAll()
+
+ def testReadGroupInto_WrongFieldNumberInEndGroupTag(self):
+ expected_field_number = 10
+ field_number = expected_field_number + 1
+ num_bytes = 5
+ d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes)
+ self.mock_stream.SkipBytes(num_bytes)
+ # Wrong field number, right wire type.
+ self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
+ field_number, wire_format.WIRETYPE_END_GROUP))
+ self.mox.ReplayAll()
+ self.assertRaises(message.DecodeError,
+ d.ReadGroupInto, expected_field_number,
+ self.mock_message)
+ self.mox.VerifyAll()
+
+ def testSkipBytes(self):
+ d = decoder.Decoder('')
+ num_bytes = 1024
+ self.mock_stream.SkipBytes(num_bytes)
+ d._stream = self.mock_stream
+ self.mox.ReplayAll()
+ d.SkipBytes(num_bytes)
+ self.mox.VerifyAll()
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
new file mode 100755
index 00000000..625d0326
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -0,0 +1,97 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Unittest for google.protobuf.internal.descriptor."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import unittest
+from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor
+
+class DescriptorTest(unittest.TestCase):
+
+ def setUp(self):
+ self.my_enum = descriptor.EnumDescriptor(
+ name='ForeignEnum',
+ full_name='protobuf_unittest.ForeignEnum',
+ filename='ForeignEnum',
+ values=[
+ descriptor.EnumValueDescriptor(name='FOREIGN_FOO', index=0, number=4),
+ descriptor.EnumValueDescriptor(name='FOREIGN_BAR', index=1, number=5),
+ descriptor.EnumValueDescriptor(name='FOREIGN_BAZ', index=2, number=6),
+ ])
+ self.my_message = descriptor.Descriptor(
+ name='NestedMessage',
+ full_name='protobuf_unittest.TestAllTypes.NestedMessage',
+ filename='some/filename/some.proto',
+ containing_type=None,
+ fields=[
+ descriptor.FieldDescriptor(
+ name='bb',
+ full_name='protobuf_unittest.TestAllTypes.NestedMessage.bb',
+ index=0, number=1,
+ type=5, cpp_type=1, label=1,
+ default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None),
+ ],
+ nested_types=[],
+ enum_types=[
+ self.my_enum,
+ ],
+ extensions=[])
+ self.my_method = descriptor.MethodDescriptor(
+ name='Bar',
+ full_name='protobuf_unittest.TestService.Bar',
+ index=0,
+ containing_service=None,
+ input_type=None,
+ output_type=None)
+ self.my_service = descriptor.ServiceDescriptor(
+ name='TestServiceWithOptions',
+ full_name='protobuf_unittest.TestServiceWithOptions',
+ index=0,
+ methods=[
+ self.my_method
+ ])
+
+ 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)
+
+ 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())
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
new file mode 100755
index 00000000..29c78b23
--- /dev/null
+++ b/python/google/protobuf/internal/encoder.py
@@ -0,0 +1,192 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Class for encoding protocol message primitives.
+
+Contains the logic for encoding every logical protocol field type
+into one of the 5 physical wire types.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+from google.protobuf import message
+from google.protobuf.internal import wire_format
+from google.protobuf.internal import output_stream
+
+
+# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
+# that the interface is strongly inspired by WireFormat from the C++ proto2
+# implementation.
+
+
+class Encoder(object):
+
+ """Encodes logical protocol buffer fields to the wire format."""
+
+ def __init__(self):
+ self._stream = output_stream.OutputStream()
+
+ def ToString(self):
+ """Returns all values encoded in this object as a string."""
+ return self._stream.ToString()
+
+ # All the Append*() methods below first append a tag+type pair to the buffer
+ # before appending the specified value.
+
+ def AppendInt32(self, field_number, value):
+ """Appends a 32-bit integer to our buffer, varint-encoded."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ self._stream.AppendVarint32(value)
+
+ def AppendInt64(self, field_number, value):
+ """Appends a 64-bit integer to our buffer, varint-encoded."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ self._stream.AppendVarint64(value)
+
+ def AppendUInt32(self, field_number, unsigned_value):
+ """Appends an unsigned 32-bit integer to our buffer, varint-encoded."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ self._stream.AppendVarUInt32(unsigned_value)
+
+ def AppendUInt64(self, field_number, unsigned_value):
+ """Appends an unsigned 64-bit integer to our buffer, varint-encoded."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ self._stream.AppendVarUInt64(unsigned_value)
+
+ def AppendSInt32(self, field_number, value):
+ """Appends a 32-bit integer to our buffer, zigzag-encoded and then
+ varint-encoded.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ zigzag_value = wire_format.ZigZagEncode(value)
+ self._stream.AppendVarUInt32(zigzag_value)
+
+ def AppendSInt64(self, field_number, value):
+ """Appends a 64-bit integer to our buffer, zigzag-encoded and then
+ varint-encoded.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+ zigzag_value = wire_format.ZigZagEncode(value)
+ self._stream.AppendVarUInt64(zigzag_value)
+
+ def AppendFixed32(self, field_number, unsigned_value):
+ """Appends an unsigned 32-bit integer to our buffer, in little-endian
+ byte-order.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+ self._stream.AppendLittleEndian32(unsigned_value)
+
+ def AppendFixed64(self, field_number, unsigned_value):
+ """Appends an unsigned 64-bit integer to our buffer, in little-endian
+ byte-order.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+ self._stream.AppendLittleEndian64(unsigned_value)
+
+ def AppendSFixed32(self, field_number, value):
+ """Appends a signed 32-bit integer to our buffer, in little-endian
+ byte-order.
+ """
+ sign = (value & 0x80000000) and -1 or 0
+ if value >> 32 != sign:
+ raise message.EncodeError('SFixed32 out of range: %d' % value)
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+ self._stream.AppendLittleEndian32(value & 0xffffffff)
+
+ def AppendSFixed64(self, field_number, value):
+ """Appends a signed 64-bit integer to our buffer, in little-endian
+ byte-order.
+ """
+ sign = (value & 0x8000000000000000) and -1 or 0
+ if value >> 64 != sign:
+ raise message.EncodeError('SFixed64 out of range: %d' % value)
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+ self._stream.AppendLittleEndian64(value & 0xffffffffffffffff)
+
+ def AppendFloat(self, field_number, value):
+ """Appends a floating-point number to our buffer."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+ self._stream.AppendRawBytes(struct.pack('f', value))
+
+ def AppendDouble(self, field_number, value):
+ """Appends a double-precision floating-point number to our buffer."""
+ self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+ self._stream.AppendRawBytes(struct.pack('d', value))
+
+ def AppendBool(self, field_number, value):
+ """Appends a boolean to our buffer."""
+ self.AppendInt32(field_number, value)
+
+ def AppendEnum(self, field_number, value):
+ """Appends an enum value to our buffer."""
+ self.AppendInt32(field_number, value)
+
+ def AppendString(self, field_number, value):
+ """Appends a length-prefixed string to our buffer, with the
+ length varint-encoded.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+ self._stream.AppendVarUInt32(len(value))
+ self._stream.AppendRawBytes(value)
+
+ def AppendBytes(self, field_number, value):
+ """Appends a length-prefixed sequence of bytes to our buffer, with the
+ length varint-encoded.
+ """
+ self.AppendString(field_number, value)
+
+ # TODO(robinson): For AppendGroup() and AppendMessage(), we'd really like to
+ # avoid the extra string copy here. We can do so if we widen the Message
+ # interface to be able to serialize to a stream in addition to a string. The
+ # challenge when thinking ahead to the Python/C API implementation of Message
+ # is finding a stream-like Python thing to which we can write raw bytes
+ # from C. I'm not sure such a thing exists(?). (array.array is pretty much
+ # what we want, but it's not directly exposed in the Python/C API).
+
+ def AppendGroup(self, field_number, group):
+ """Appends a group to our buffer.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_START_GROUP)
+ self._stream.AppendRawBytes(group.SerializeToString())
+ self._AppendTag(field_number, wire_format.WIRETYPE_END_GROUP)
+
+ def AppendMessage(self, field_number, msg):
+ """Appends a nested message to our buffer.
+ """
+ self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+ self._stream.AppendVarUInt32(msg.ByteSize())
+ self._stream.AppendRawBytes(msg.SerializeToString())
+
+ def AppendMessageSetItem(self, field_number, msg):
+ """Appends an item using the message set wire format.
+
+ The message set message looks like this:
+ message MessageSet {
+ repeated group Item = 1 {
+ required int32 type_id = 2;
+ required string message = 3;
+ }
+ }
+ """
+ self._AppendTag(1, wire_format.WIRETYPE_START_GROUP)
+ self.AppendInt32(2, field_number)
+ self.AppendMessage(3, msg)
+ self._AppendTag(1, wire_format.WIRETYPE_END_GROUP)
+
+ def _AppendTag(self, field_number, wire_type):
+ """Appends a tag containing field number and wire type information."""
+ self._stream.AppendVarUInt32(wire_format.PackTag(field_number, wire_type))
diff --git a/python/google/protobuf/internal/encoder_test.py b/python/google/protobuf/internal/encoder_test.py
new file mode 100755
index 00000000..5d690da7
--- /dev/null
+++ b/python/google/protobuf/internal/encoder_test.py
@@ -0,0 +1,211 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Test for google.protobuf.internal.encoder."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+import logging
+import unittest
+import mox
+from google.protobuf.internal import wire_format
+from google.protobuf.internal import encoder
+from google.protobuf.internal import output_stream
+from google.protobuf import message
+
+
+class EncoderTest(unittest.TestCase):
+
+ def setUp(self):
+ self.mox = mox.Mox()
+ self.encoder = encoder.Encoder()
+ self.mock_stream = self.mox.CreateMock(output_stream.OutputStream)
+ self.mock_message = self.mox.CreateMock(message.Message)
+ self.encoder._stream = self.mock_stream
+
+ def PackTag(self, field_number, wire_type):
+ return wire_format.PackTag(field_number, wire_type)
+
+ def AppendScalarTestHelper(self, test_name, encoder_method,
+ expected_stream_method_name,
+ wire_type, field_value, expected_value=None):
+ """Helper for testAppendScalars.
+
+ Calls one of the Encoder methods, and ensures that the Encoder
+ in turn makes the expected calls into its OutputStream.
+
+ Args:
+ test_name: Name of this test, used only for logging.
+ encoder_method: Callable on self.encoder, which should
+ accept |field_value| as an argument. This is the Encoder
+ method we're testing.
+ expected_stream_method_name: (string) Name of the OutputStream
+ method we expect Encoder to call to actually put the value
+ on the wire.
+ wire_type: The WIRETYPE_* constant we expect encoder to
+ use in the specified encoder_method.
+ field_value: The value we're trying to encode. Passed
+ into encoder_method.
+ expected_value: The value we expect Encoder to pass into
+ the OutputStream method. If None, we expect field_value
+ to pass through unmodified.
+ """
+ if expected_value is None:
+ expected_value = field_value
+
+ logging.info('Testing %s scalar output.\n'
+ 'Calling %r(%r), and expecting that to call the '
+ 'stream method %s(%r).' % (
+ test_name, encoder_method, field_value,
+ expected_stream_method_name, expected_value))
+
+ field_number = 10
+ # Should first append the field number and type information.
+ self.mock_stream.AppendVarUInt32(self.PackTag(field_number, wire_type))
+ # If we're length-delimited, we should then append the length.
+ if wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED:
+ self.mock_stream.AppendVarUInt32(len(field_value))
+ # Should then append the value itself.
+ # We have to use names instead of methods to work around some
+ # mox weirdness. (ResetAll() is overzealous).
+ expected_stream_method = getattr(self.mock_stream,
+ expected_stream_method_name)
+ expected_stream_method(expected_value)
+
+ self.mox.ReplayAll()
+ encoder_method(field_number, field_value)
+ self.mox.VerifyAll()
+ self.mox.ResetAll()
+
+ def testAppendScalars(self):
+ scalar_tests = [
+ ['int32', self.encoder.AppendInt32, 'AppendVarint32',
+ wire_format.WIRETYPE_VARINT, 0],
+ ['int64', self.encoder.AppendInt64, 'AppendVarint64',
+ wire_format.WIRETYPE_VARINT, 0],
+ ['uint32', self.encoder.AppendUInt32, 'AppendVarUInt32',
+ wire_format.WIRETYPE_VARINT, 0],
+ ['uint64', self.encoder.AppendUInt64, 'AppendVarUInt64',
+ wire_format.WIRETYPE_VARINT, 0],
+ ['fixed32', self.encoder.AppendFixed32, 'AppendLittleEndian32',
+ wire_format.WIRETYPE_FIXED32, 0],
+ ['fixed64', self.encoder.AppendFixed64, 'AppendLittleEndian64',
+ wire_format.WIRETYPE_FIXED64, 0],
+ ['sfixed32', self.encoder.AppendSFixed32, 'AppendLittleEndian32',
+ wire_format.WIRETYPE_FIXED32, -1, 0xffffffff],
+ ['sfixed64', self.encoder.AppendSFixed64, 'AppendLittleEndian64',
+ wire_format.WIRETYPE_FIXED64, -1, 0xffffffffffffffff],
+ ['float', self.encoder.AppendFloat, 'AppendRawBytes',
+ wire_format.WIRETYPE_FIXED32, 0.0, struct.pack('f', 0.0)],
+ ['double', self.encoder.AppendDouble, 'AppendRawBytes',
+ wire_format.WIRETYPE_FIXED64, 0.0, struct.pack('d', 0.0)],
+ ['bool', self.encoder.AppendBool, 'AppendVarint32',
+ wire_format.WIRETYPE_VARINT, False],
+ ['enum', self.encoder.AppendEnum, 'AppendVarint32',
+ wire_format.WIRETYPE_VARINT, 0],
+ ['string', self.encoder.AppendString, 'AppendRawBytes',
+ wire_format.WIRETYPE_LENGTH_DELIMITED,
+ "You're in a maze of twisty little passages, all alike."],
+ # We test zigzag encoding routines more extensively below.
+ ['sint32', self.encoder.AppendSInt32, 'AppendVarUInt32',
+ wire_format.WIRETYPE_VARINT, -1, 1],
+ ['sint64', self.encoder.AppendSInt64, 'AppendVarUInt64',
+ wire_format.WIRETYPE_VARINT, -1, 1],
+ ]
+ # Ensure that we're testing different Encoder methods and using
+ # different test names in all test cases above.
+ self.assertEqual(len(scalar_tests), len(set(t[0] for t in scalar_tests)))
+ self.assertEqual(len(scalar_tests), len(set(t[1] for t in scalar_tests)))
+ for args in scalar_tests:
+ self.AppendScalarTestHelper(*args)
+
+ def testAppendGroup(self):
+ field_number = 23
+ # Should first append the start-group marker.
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(field_number, wire_format.WIRETYPE_START_GROUP))
+ # Should then serialize itself.
+ self.mock_message.SerializeToString().AndReturn('foo')
+ self.mock_stream.AppendRawBytes('foo')
+ # Should finally append the end-group marker.
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(field_number, wire_format.WIRETYPE_END_GROUP))
+
+ self.mox.ReplayAll()
+ self.encoder.AppendGroup(field_number, self.mock_message)
+ self.mox.VerifyAll()
+
+ def testAppendMessage(self):
+ field_number = 23
+ byte_size = 42
+ # Should first append the field number and type information.
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED))
+ # Should then append its length.
+ self.mock_message.ByteSize().AndReturn(byte_size)
+ self.mock_stream.AppendVarUInt32(byte_size)
+ # Should then serialize itself to the encoder.
+ self.mock_message.SerializeToString().AndReturn('foo')
+ self.mock_stream.AppendRawBytes('foo')
+
+ self.mox.ReplayAll()
+ self.encoder.AppendMessage(field_number, self.mock_message)
+ self.mox.VerifyAll()
+
+ def testAppendMessageSetItem(self):
+ field_number = 23
+ byte_size = 42
+ # Should first append the field number and type information.
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(1, wire_format.WIRETYPE_START_GROUP))
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(2, wire_format.WIRETYPE_VARINT))
+ self.mock_stream.AppendVarint32(field_number)
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(3, wire_format.WIRETYPE_LENGTH_DELIMITED))
+ # Should then append its length.
+ self.mock_message.ByteSize().AndReturn(byte_size)
+ self.mock_stream.AppendVarUInt32(byte_size)
+ # Should then serialize itself to the encoder.
+ self.mock_message.SerializeToString().AndReturn('foo')
+ self.mock_stream.AppendRawBytes('foo')
+ self.mock_stream.AppendVarUInt32(
+ self.PackTag(1, wire_format.WIRETYPE_END_GROUP))
+
+ self.mox.ReplayAll()
+ self.encoder.AppendMessageSetItem(field_number, self.mock_message)
+ self.mox.VerifyAll()
+
+ def testAppendSFixed(self):
+ # Most of our bounds-checking is done in output_stream.py,
+ # but encoder.py is responsible for transforming signed
+ # fixed-width integers into unsigned ones, so we test here
+ # to ensure that we're not losing any entropy when we do
+ # that conversion.
+ field_number = 10
+ self.assertRaises(message.EncodeError, self.encoder.AppendSFixed32,
+ 10, wire_format.UINT32_MAX + 1)
+ self.assertRaises(message.EncodeError, self.encoder.AppendSFixed32,
+ 10, -(1 << 32))
+ self.assertRaises(message.EncodeError, self.encoder.AppendSFixed64,
+ 10, wire_format.UINT64_MAX + 1)
+ self.assertRaises(message.EncodeError, self.encoder.AppendSFixed64,
+ 10, -(1 << 64))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
new file mode 100755
index 00000000..02f993f7
--- /dev/null
+++ b/python/google/protobuf/internal/generator_test.py
@@ -0,0 +1,84 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+# 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 //net/proto2/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 import unittest_mset_pb2
+from google.protobuf import unittest_pb2
+
+
+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 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_pb2.TestMessageSet()
+ self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/input_stream.py b/python/google/protobuf/internal/input_stream.py
new file mode 100755
index 00000000..9f3b0f5a
--- /dev/null
+++ b/python/google/protobuf/internal/input_stream.py
@@ -0,0 +1,211 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""InputStream is the primitive interface for reading bits from the wire.
+
+All protocol buffer deserialization can be expressed in terms of
+the InputStream primitives provided here.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+from google.protobuf import message
+from google.protobuf.internal import wire_format
+
+
+# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
+# that the interface is strongly inspired by CodedInputStream from the C++
+# proto2 implementation.
+
+
+class InputStream(object):
+
+ """Contains all logic for reading bits, and dealing with stream position.
+
+ If an InputStream method ever raises an exception, the stream is left
+ in an indeterminate state and is not safe for further use.
+ """
+
+ def __init__(self, s):
+ # What we really want is something like array('B', s), where elements we
+ # read from the array are already given to us as one-byte integers. BUT
+ # using array() instead of buffer() would force full string copies to result
+ # from each GetSubBuffer() call.
+ #
+ # So, if the N serialized bytes of a single protocol buffer object are
+ # split evenly between 2 child messages, and so on recursively, using
+ # array('B', s) instead of buffer() would incur an additional N*logN bytes
+ # copied during deserialization.
+ #
+ # The higher constant overhead of having to ord() for every byte we read
+ # from the buffer in _ReadVarintHelper() could definitely lead to worse
+ # performance in many real-world scenarios, even if the asymptotic
+ # complexity is better. However, our real answer is that the mythical
+ # Python/C extension module output mode for the protocol compiler will
+ # be blazing-fast and will eliminate most use of this class anyway.
+ self._buffer = buffer(s)
+ self._pos = 0
+
+ def EndOfStream(self):
+ """Returns true iff we're at the end of the stream.
+ If this returns true, then a call to any other InputStream method
+ will raise an exception.
+ """
+ return self._pos >= len(self._buffer)
+
+ def Position(self):
+ """Returns the current position in the stream, or equivalently, the
+ number of bytes read so far.
+ """
+ return self._pos
+
+ def GetSubBuffer(self, size=None):
+ """Returns a sequence-like object that represents a portion of our
+ underlying sequence.
+
+ Position 0 in the returned object corresponds to self.Position()
+ in this stream.
+
+ If size is specified, then the returned object ends after the
+ next "size" bytes in this stream. If size is not specified,
+ then the returned object ends at the end of this stream.
+
+ We guarantee that the returned object R supports the Python buffer
+ interface (and thus that the call buffer(R) will work).
+
+ Note that the returned buffer is read-only.
+
+ The intended use for this method is for nested-message and nested-group
+ deserialization, where we want to make a recursive MergeFromString()
+ call on the portion of the original sequence that contains the serialized
+ nested message. (And we'd like to do so without making unnecessary string
+ copies).
+
+ REQUIRES: size is nonnegative.
+ """
+ # Note that buffer() doesn't perform any actual string copy.
+ if size is None:
+ return buffer(self._buffer, self._pos)
+ else:
+ if size < 0:
+ raise message.DecodeError('Negative size %d' % size)
+ return buffer(self._buffer, self._pos, size)
+
+ def SkipBytes(self, num_bytes):
+ """Skip num_bytes bytes ahead, or go to the end of the stream, whichever
+ comes first.
+
+ REQUIRES: num_bytes is nonnegative.
+ """
+ if num_bytes < 0:
+ raise message.DecodeError('Negative num_bytes %d' % num_bytes)
+ self._pos += num_bytes
+ self._pos = min(self._pos, len(self._buffer))
+
+ def ReadString(self, size):
+ """Reads up to 'size' bytes from the stream, stopping early
+ only if we reach the end of the stream. Returns the bytes read
+ as a string.
+ """
+ if size < 0:
+ raise message.DecodeError('Negative size %d' % size)
+ s = (self._buffer[self._pos : self._pos + size])
+ self._pos += len(s) # Only advance by the number of bytes actually read.
+ return s
+
+ def ReadLittleEndian32(self):
+ """Interprets the next 4 bytes of the stream as a little-endian
+ encoded, unsiged 32-bit integer, and returns that integer.
+ """
+ try:
+ i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN,
+ self._buffer[self._pos : self._pos + 4])
+ self._pos += 4
+ return i[0] # unpack() result is a 1-element tuple.
+ except struct.error, e:
+ raise message.DecodeError(e)
+
+ def ReadLittleEndian64(self):
+ """Interprets the next 8 bytes of the stream as a little-endian
+ encoded, unsiged 64-bit integer, and returns that integer.
+ """
+ try:
+ i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN,
+ self._buffer[self._pos : self._pos + 8])
+ self._pos += 8
+ return i[0] # unpack() result is a 1-element tuple.
+ except struct.error, e:
+ raise message.DecodeError(e)
+
+ def ReadVarint32(self):
+ """Reads a varint from the stream, interprets this varint
+ as a signed, 32-bit integer, and returns the integer.
+ """
+ i = self.ReadVarint64()
+ if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX:
+ raise message.DecodeError('Value out of range for int32: %d' % i)
+ return int(i)
+
+ def ReadVarUInt32(self):
+ """Reads a varint from the stream, interprets this varint
+ as an unsigned, 32-bit integer, and returns the integer.
+ """
+ i = self.ReadVarUInt64()
+ if i > wire_format.UINT32_MAX:
+ raise message.DecodeError('Value out of range for uint32: %d' % i)
+ return i
+
+ def ReadVarint64(self):
+ """Reads a varint from the stream, interprets this varint
+ as a signed, 64-bit integer, and returns the integer.
+ """
+ i = self.ReadVarUInt64()
+ if i > wire_format.INT64_MAX:
+ i -= (1 << 64)
+ return i
+
+ def ReadVarUInt64(self):
+ """Reads a varint from the stream, interprets this varint
+ as an unsigned, 64-bit integer, and returns the integer.
+ """
+ i = self._ReadVarintHelper()
+ if not 0 <= i <= wire_format.UINT64_MAX:
+ raise message.DecodeError('Value out of range for uint64: %d' % i)
+ return i
+
+ def _ReadVarintHelper(self):
+ """Helper for the various varint-reading methods above.
+ Reads an unsigned, varint-encoded integer from the stream and
+ returns this integer.
+
+ Does no bounds checking except to ensure that we read at most as many bytes
+ as could possibly be present in a varint-encoded 64-bit number.
+ """
+ result = 0
+ shift = 0
+ while 1:
+ if shift >= 64:
+ raise message.DecodeError('Too many bytes when decoding varint.')
+ try:
+ b = ord(self._buffer[self._pos])
+ except IndexError:
+ raise message.DecodeError('Truncated varint.')
+ self._pos += 1
+ result |= ((b & 0x7f) << shift)
+ shift += 7
+ if not (b & 0x80):
+ return result
diff --git a/python/google/protobuf/internal/input_stream_test.py b/python/google/protobuf/internal/input_stream_test.py
new file mode 100755
index 00000000..2d685545
--- /dev/null
+++ b/python/google/protobuf/internal/input_stream_test.py
@@ -0,0 +1,279 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Test for google.protobuf.internal.input_stream."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import unittest
+from google.protobuf import message
+from google.protobuf.internal import wire_format
+from google.protobuf.internal import input_stream
+
+
+class InputStreamTest(unittest.TestCase):
+
+ def testEndOfStream(self):
+ stream = input_stream.InputStream('abcd')
+ self.assertFalse(stream.EndOfStream())
+ self.assertEqual('abcd', stream.ReadString(10))
+ self.assertTrue(stream.EndOfStream())
+
+ def testPosition(self):
+ stream = input_stream.InputStream('abcd')
+ self.assertEqual(0, stream.Position())
+ self.assertEqual(0, stream.Position()) # No side-effects.
+ stream.ReadString(1)
+ self.assertEqual(1, stream.Position())
+ stream.ReadString(1)
+ self.assertEqual(2, stream.Position())
+ stream.ReadString(10)
+ self.assertEqual(4, stream.Position()) # Can't go past end of stream.
+
+ def testGetSubBuffer(self):
+ stream = input_stream.InputStream('abcd')
+ # Try leaving out the size.
+ self.assertEqual('abcd', str(stream.GetSubBuffer()))
+ stream.SkipBytes(1)
+ # GetSubBuffer() always starts at current size.
+ self.assertEqual('bcd', str(stream.GetSubBuffer()))
+ # Try 0-size.
+ self.assertEqual('', str(stream.GetSubBuffer(0)))
+ # Negative sizes should raise an error.
+ self.assertRaises(message.DecodeError, stream.GetSubBuffer, -1)
+ # Positive sizes should work as expected.
+ self.assertEqual('b', str(stream.GetSubBuffer(1)))
+ self.assertEqual('bc', str(stream.GetSubBuffer(2)))
+ # Sizes longer than remaining bytes in the buffer should
+ # return the whole remaining buffer.
+ self.assertEqual('bcd', str(stream.GetSubBuffer(1000)))
+
+ def testSkipBytes(self):
+ stream = input_stream.InputStream('')
+ # Skipping bytes when at the end of stream
+ # should have no effect.
+ stream.SkipBytes(0)
+ stream.SkipBytes(1)
+ stream.SkipBytes(2)
+ self.assertTrue(stream.EndOfStream())
+ self.assertEqual(0, stream.Position())
+
+ # Try skipping within a stream.
+ stream = input_stream.InputStream('abcd')
+ self.assertEqual(0, stream.Position())
+ stream.SkipBytes(1)
+ self.assertEqual(1, stream.Position())
+ stream.SkipBytes(10) # Can't skip past the end.
+ self.assertEqual(4, stream.Position())
+
+ # Ensure that a negative skip raises an exception.
+ stream = input_stream.InputStream('abcd')
+ stream.SkipBytes(1)
+ self.assertRaises(message.DecodeError, stream.SkipBytes, -1)
+
+ def testReadString(self):
+ s = 'abcd'
+ # Also test going past the total stream length.
+ for i in range(len(s) + 10):
+ stream = input_stream.InputStream(s)
+ self.assertEqual(s[:i], stream.ReadString(i))
+ self.assertEqual(min(i, len(s)), stream.Position())
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadString, -1)
+
+ def EnsureFailureOnEmptyStream(self, input_stream_method):
+ """Helper for integer-parsing tests below.
+ Ensures that the given InputStream method raises a DecodeError
+ if called on a stream with no bytes remaining.
+ """
+ stream = input_stream.InputStream('')
+ self.assertRaises(message.DecodeError, input_stream_method, stream)
+
+ def testReadLittleEndian32(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadLittleEndian32)
+ s = ''
+ # Read 0.
+ s += '\x00\x00\x00\x00'
+ # Read 1.
+ s += '\x01\x00\x00\x00'
+ # Read a bunch of different bytes.
+ s += '\x01\x02\x03\x04'
+ # Read max unsigned 32-bit int.
+ s += '\xff\xff\xff\xff'
+ # Try a read with fewer than 4 bytes left in the stream.
+ s += '\x00\x00\x00'
+ stream = input_stream.InputStream(s)
+ self.assertEqual(0, stream.ReadLittleEndian32())
+ self.assertEqual(4, stream.Position())
+ self.assertEqual(1, stream.ReadLittleEndian32())
+ self.assertEqual(8, stream.Position())
+ self.assertEqual(0x04030201, stream.ReadLittleEndian32())
+ self.assertEqual(12, stream.Position())
+ self.assertEqual(wire_format.UINT32_MAX, stream.ReadLittleEndian32())
+ self.assertEqual(16, stream.Position())
+ self.assertRaises(message.DecodeError, stream.ReadLittleEndian32)
+
+ def testReadLittleEndian64(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadLittleEndian64)
+ s = ''
+ # Read 0.
+ s += '\x00\x00\x00\x00\x00\x00\x00\x00'
+ # Read 1.
+ s += '\x01\x00\x00\x00\x00\x00\x00\x00'
+ # Read a bunch of different bytes.
+ s += '\x01\x02\x03\x04\x05\x06\x07\x08'
+ # Read max unsigned 64-bit int.
+ s += '\xff\xff\xff\xff\xff\xff\xff\xff'
+ # Try a read with fewer than 8 bytes left in the stream.
+ s += '\x00\x00\x00'
+ stream = input_stream.InputStream(s)
+ self.assertEqual(0, stream.ReadLittleEndian64())
+ self.assertEqual(8, stream.Position())
+ self.assertEqual(1, stream.ReadLittleEndian64())
+ self.assertEqual(16, stream.Position())
+ self.assertEqual(0x0807060504030201, stream.ReadLittleEndian64())
+ self.assertEqual(24, stream.Position())
+ self.assertEqual(wire_format.UINT64_MAX, stream.ReadLittleEndian64())
+ self.assertEqual(32, stream.Position())
+ self.assertRaises(message.DecodeError, stream.ReadLittleEndian64)
+
+ def ReadVarintSuccessTestHelper(self, varints_and_ints, read_method):
+ """Helper for tests below that test successful reads of various varints.
+
+ Args:
+ varints_and_ints: Iterable of (str, integer) pairs, where the string
+ gives the wire encoding and the integer gives the value we expect
+ to be returned by the read_method upon encountering this string.
+ read_method: Unbound InputStream method that is capable of reading
+ the encoded strings provided in the first elements of varints_and_ints.
+ """
+ s = ''.join(s for s, i in varints_and_ints)
+ stream = input_stream.InputStream(s)
+ expected_pos = 0
+ self.assertEqual(expected_pos, stream.Position())
+ for s, expected_int in varints_and_ints:
+ self.assertEqual(expected_int, read_method(stream))
+ expected_pos += len(s)
+ self.assertEqual(expected_pos, stream.Position())
+
+ def testReadVarint32Success(self):
+ varints_and_ints = [
+ ('\x00', 0),
+ ('\x01', 1),
+ ('\x7f', 127),
+ ('\x80\x01', 128),
+ ('\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01', -1),
+ ('\xff\xff\xff\xff\x07', wire_format.INT32_MAX),
+ ('\x80\x80\x80\x80\xf8\xff\xff\xff\xff\x01', wire_format.INT32_MIN),
+ ]
+ self.ReadVarintSuccessTestHelper(varints_and_ints,
+ input_stream.InputStream.ReadVarint32)
+
+ def testReadVarint32Failure(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarint32)
+
+ # Try and fail to read INT32_MAX + 1.
+ s = '\x80\x80\x80\x80\x08'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarint32)
+
+ # Try and fail to read INT32_MIN - 1.
+ s = '\xfe\xff\xff\xff\xf7\xff\xff\xff\xff\x01'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarint32)
+
+ # Try and fail to read something that looks like
+ # a varint with more than 10 bytes.
+ s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarint32)
+
+ def testReadVarUInt32Success(self):
+ varints_and_ints = [
+ ('\x00', 0),
+ ('\x01', 1),
+ ('\x7f', 127),
+ ('\x80\x01', 128),
+ ('\xff\xff\xff\xff\x0f', wire_format.UINT32_MAX),
+ ]
+ self.ReadVarintSuccessTestHelper(varints_and_ints,
+ input_stream.InputStream.ReadVarUInt32)
+
+ def testReadVarUInt32Failure(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarUInt32)
+ # Try and fail to read UINT32_MAX + 1
+ s = '\x80\x80\x80\x80\x10'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarUInt32)
+
+ # Try and fail to read something that looks like
+ # a varint with more than 10 bytes.
+ s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarUInt32)
+
+ def testReadVarint64Success(self):
+ varints_and_ints = [
+ ('\x00', 0),
+ ('\x01', 1),
+ ('\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01', -1),
+ ('\x7f', 127),
+ ('\x80\x01', 128),
+ ('\xff\xff\xff\xff\xff\xff\xff\xff\x7f', wire_format.INT64_MAX),
+ ('\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01', wire_format.INT64_MIN),
+ ]
+ self.ReadVarintSuccessTestHelper(varints_and_ints,
+ input_stream.InputStream.ReadVarint64)
+
+ def testReadVarint64Failure(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarint64)
+ # Try and fail to read something with the mythical 64th bit set.
+ s = '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarint64)
+
+ # Try and fail to read something that looks like
+ # a varint with more than 10 bytes.
+ s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarint64)
+
+ def testReadVarUInt64Success(self):
+ varints_and_ints = [
+ ('\x00', 0),
+ ('\x01', 1),
+ ('\x7f', 127),
+ ('\x80\x01', 128),
+ ('\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01', 1 << 63),
+ ]
+ self.ReadVarintSuccessTestHelper(varints_and_ints,
+ input_stream.InputStream.ReadVarUInt64)
+
+ def testReadVarUInt64Failure(self):
+ self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarUInt64)
+ # Try and fail to read something with the mythical 64th bit set.
+ s = '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarUInt64)
+
+ # Try and fail to read something that looks like
+ # a varint with more than 10 bytes.
+ s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'
+ stream = input_stream.InputStream(s)
+ self.assertRaises(message.DecodeError, stream.ReadVarUInt64)
+
+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 100755
index 00000000..3747909e
--- /dev/null
+++ b/python/google/protobuf/internal/message_listener.py
@@ -0,0 +1,55 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""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 transitions to nonempty and for invalidations of cached
+ byte sizes. Meant to be registered via Message._SetListener().
+ """
+
+ def TransitionToNonempty(self):
+ """Called the *first* time that this message becomes nonempty.
+ Implementations are free (but not required) to call this method multiple
+ times after the message has become nonempty.
+ """
+ raise NotImplementedError
+
+ def ByteSizeDirty(self):
+ """Called *every* time the cached byte size value
+ for this object is invalidated (transitions from being
+ "clean" to "dirty").
+ """
+ raise NotImplementedError
+
+
+class NullMessageListener(object):
+
+ """No-op MessageListener implementation."""
+
+ def TransitionToNonempty(self):
+ pass
+
+ def ByteSizeDirty(self):
+ pass
diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto
new file mode 100644
index 00000000..48df6f55
--- /dev/null
+++ b/python/google/protobuf/internal/more_extensions.proto
@@ -0,0 +1,44 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: robinson@google.com (Will Robinson)
+
+
+package google.protobuf.internal;
+
+
+message TopLevelMessage {
+ optional ExtendedMessage submessage = 1;
+}
+
+
+message ExtendedMessage {
+ extensions 1 to max;
+}
+
+
+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_messages.proto b/python/google/protobuf/internal/more_messages.proto
new file mode 100644
index 00000000..bfa12273
--- /dev/null
+++ b/python/google/protobuf/internal/more_messages.proto
@@ -0,0 +1,37 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: robinson@google.com (Will Robinson)
+
+
+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;
+}
diff --git a/python/google/protobuf/internal/output_stream.py b/python/google/protobuf/internal/output_stream.py
new file mode 100755
index 00000000..767e9725
--- /dev/null
+++ b/python/google/protobuf/internal/output_stream.py
@@ -0,0 +1,112 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""OutputStream is the primitive interface for sticking bits on the wire.
+
+All protocol buffer serialization can be expressed in terms of
+the OutputStream primitives provided here.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import array
+import struct
+from google.protobuf import message
+from google.protobuf.internal import wire_format
+
+
+
+# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
+# that the interface is strongly inspired by CodedOutputStream from the C++
+# proto2 implementation.
+
+
+class OutputStream(object):
+
+ """Contains all logic for writing bits, and ToString() to get the result."""
+
+ def __init__(self):
+ self._buffer = array.array('B')
+
+ def AppendRawBytes(self, raw_bytes):
+ """Appends raw_bytes to our internal buffer."""
+ self._buffer.fromstring(raw_bytes)
+
+ def AppendLittleEndian32(self, unsigned_value):
+ """Appends an unsigned 32-bit integer to the internal buffer,
+ in little-endian byte order.
+ """
+ if not 0 <= unsigned_value <= wire_format.UINT32_MAX:
+ raise message.EncodeError(
+ 'Unsigned 32-bit out of range: %d' % unsigned_value)
+ self._buffer.fromstring(struct.pack(
+ wire_format.FORMAT_UINT32_LITTLE_ENDIAN, unsigned_value))
+
+ def AppendLittleEndian64(self, unsigned_value):
+ """Appends an unsigned 64-bit integer to the internal buffer,
+ in little-endian byte order.
+ """
+ if not 0 <= unsigned_value <= wire_format.UINT64_MAX:
+ raise message.EncodeError(
+ 'Unsigned 64-bit out of range: %d' % unsigned_value)
+ self._buffer.fromstring(struct.pack(
+ wire_format.FORMAT_UINT64_LITTLE_ENDIAN, unsigned_value))
+
+ def AppendVarint32(self, value):
+ """Appends a signed 32-bit integer to the internal buffer,
+ encoded as a varint. (Note that a negative varint32 will
+ always require 10 bytes of space.)
+ """
+ if not wire_format.INT32_MIN <= value <= wire_format.INT32_MAX:
+ raise message.EncodeError('Value out of range: %d' % value)
+ self.AppendVarint64(value)
+
+ def AppendVarUInt32(self, value):
+ """Appends an unsigned 32-bit integer to the internal buffer,
+ encoded as a varint.
+ """
+ if not 0 <= value <= wire_format.UINT32_MAX:
+ raise message.EncodeError('Value out of range: %d' % value)
+ self.AppendVarUInt64(value)
+
+ def AppendVarint64(self, value):
+ """Appends a signed 64-bit integer to the internal buffer,
+ encoded as a varint.
+ """
+ if not wire_format.INT64_MIN <= value <= wire_format.INT64_MAX:
+ raise message.EncodeError('Value out of range: %d' % value)
+ if value < 0:
+ value += (1 << 64)
+ self.AppendVarUInt64(value)
+
+ def AppendVarUInt64(self, unsigned_value):
+ """Appends an unsigned 64-bit integer to the internal buffer,
+ encoded as a varint.
+ """
+ if not 0 <= unsigned_value <= wire_format.UINT64_MAX:
+ raise message.EncodeError('Value out of range: %d' % unsigned_value)
+ while True:
+ bits = unsigned_value & 0x7f
+ unsigned_value >>= 7
+ if unsigned_value:
+ bits |= 0x80
+ self._buffer.append(bits)
+ if not unsigned_value:
+ break
+
+ def ToString(self):
+ """Returns a string containing the bytes in our internal buffer."""
+ return self._buffer.tostring()
diff --git a/python/google/protobuf/internal/output_stream_test.py b/python/google/protobuf/internal/output_stream_test.py
new file mode 100755
index 00000000..026f6161
--- /dev/null
+++ b/python/google/protobuf/internal/output_stream_test.py
@@ -0,0 +1,162 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Test for google.protobuf.internal.output_stream."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import unittest
+from google.protobuf import message
+from google.protobuf.internal import output_stream
+from google.protobuf.internal import wire_format
+
+
+class OutputStreamTest(unittest.TestCase):
+
+ def setUp(self):
+ self.stream = output_stream.OutputStream()
+
+ def testAppendRawBytes(self):
+ # Empty string.
+ self.stream.AppendRawBytes('')
+ self.assertEqual('', self.stream.ToString())
+
+ # Nonempty string.
+ self.stream.AppendRawBytes('abc')
+ self.assertEqual('abc', self.stream.ToString())
+
+ # Ensure that we're actually appending.
+ self.stream.AppendRawBytes('def')
+ self.assertEqual('abcdef', self.stream.ToString())
+
+ def AppendNumericTestHelper(self, append_fn, values_and_strings):
+ """For each (value, expected_string) pair in values_and_strings,
+ calls an OutputStream.Append*(value) method on an OutputStream and ensures
+ that the string written to that stream matches expected_string.
+
+ Args:
+ append_fn: Unbound OutputStream method that takes an integer or
+ long value as input.
+ values_and_strings: Iterable of (value, expected_string) pairs.
+ """
+ for conversion in (int, long):
+ for value, string in values_and_strings:
+ stream = output_stream.OutputStream()
+ expected_string = ''
+ append_fn(stream, conversion(value))
+ expected_string += string
+ self.assertEqual(expected_string, stream.ToString())
+
+ def AppendOverflowTestHelper(self, append_fn, value):
+ """Calls an OutputStream.Append*(value) method and asserts
+ that the method raises message.EncodeError.
+
+ Args:
+ append_fn: Unbound OutputStream method that takes an integer or
+ long value as input.
+ value: Value to pass to append_fn which should cause an
+ message.EncodeError.
+ """
+ stream = output_stream.OutputStream()
+ self.assertRaises(message.EncodeError, append_fn, stream, value)
+
+ def testAppendLittleEndian32(self):
+ append_fn = output_stream.OutputStream.AppendLittleEndian32
+ values_and_expected_strings = [
+ (0, '\x00\x00\x00\x00'),
+ (1, '\x01\x00\x00\x00'),
+ ((1 << 32) - 1, '\xff\xff\xff\xff'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, 1 << 32)
+ self.AppendOverflowTestHelper(append_fn, -1)
+
+ def testAppendLittleEndian64(self):
+ append_fn = output_stream.OutputStream.AppendLittleEndian64
+ values_and_expected_strings = [
+ (0, '\x00\x00\x00\x00\x00\x00\x00\x00'),
+ (1, '\x01\x00\x00\x00\x00\x00\x00\x00'),
+ ((1 << 64) - 1, '\xff\xff\xff\xff\xff\xff\xff\xff'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, 1 << 64)
+ self.AppendOverflowTestHelper(append_fn, -1)
+
+ def testAppendVarint32(self):
+ append_fn = output_stream.OutputStream.AppendVarint32
+ values_and_expected_strings = [
+ (0, '\x00'),
+ (1, '\x01'),
+ (127, '\x7f'),
+ (128, '\x80\x01'),
+ (-1, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'),
+ (wire_format.INT32_MAX, '\xff\xff\xff\xff\x07'),
+ (wire_format.INT32_MIN, '\x80\x80\x80\x80\xf8\xff\xff\xff\xff\x01'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, wire_format.INT32_MAX + 1)
+ self.AppendOverflowTestHelper(append_fn, wire_format.INT32_MIN - 1)
+
+ def testAppendVarUInt32(self):
+ append_fn = output_stream.OutputStream.AppendVarUInt32
+ values_and_expected_strings = [
+ (0, '\x00'),
+ (1, '\x01'),
+ (127, '\x7f'),
+ (128, '\x80\x01'),
+ (wire_format.UINT32_MAX, '\xff\xff\xff\xff\x0f'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, -1)
+ self.AppendOverflowTestHelper(append_fn, wire_format.UINT32_MAX + 1)
+
+ def testAppendVarint64(self):
+ append_fn = output_stream.OutputStream.AppendVarint64
+ values_and_expected_strings = [
+ (0, '\x00'),
+ (1, '\x01'),
+ (127, '\x7f'),
+ (128, '\x80\x01'),
+ (-1, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'),
+ (wire_format.INT64_MAX, '\xff\xff\xff\xff\xff\xff\xff\xff\x7f'),
+ (wire_format.INT64_MIN, '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, wire_format.INT64_MAX + 1)
+ self.AppendOverflowTestHelper(append_fn, wire_format.INT64_MIN - 1)
+
+ def testAppendVarUInt64(self):
+ append_fn = output_stream.OutputStream.AppendVarUInt64
+ values_and_expected_strings = [
+ (0, '\x00'),
+ (1, '\x01'),
+ (127, '\x7f'),
+ (128, '\x80\x01'),
+ (wire_format.UINT64_MAX, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'),
+ ]
+ self.AppendNumericTestHelper(append_fn, values_and_expected_strings)
+
+ self.AppendOverflowTestHelper(append_fn, -1)
+ self.AppendOverflowTestHelper(append_fn, wire_format.UINT64_MAX + 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
new file mode 100755
index 00000000..5947f97a
--- /dev/null
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -0,0 +1,1300 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Unittest for reflection.py, which also indirectly tests the output of the
+pure-Python protocol compiler.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import operator
+
+import unittest
+# TODO(robinson): When we split this test in two, only some of these imports
+# will be necessary in each test.
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_mset_pb2
+from google.protobuf import unittest_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.internal import more_extensions_pb2
+from google.protobuf.internal import more_messages_pb2
+from google.protobuf.internal import wire_format
+from google.protobuf.internal import test_util
+from google.protobuf.internal import decoder
+
+
+class RefectionTest(unittest.TestCase):
+
+ def testSimpleHasBits(self):
+ # Test a scalar.
+ proto = unittest_pb2.TestAllTypes()
+ self.assertTrue(not 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.assertTrue(not 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.assertTrue(not 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.assertTrue(not composite_field.HasField(scalar_field_name))
+ # Assert that proto does not "have" the composite field.
+ self.assertTrue(not 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.assertTrue(not composite_field.HasField(scalar_field_name))
+ self.assertTrue(not 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))
+
+ # Finally, ensure that modifications to the old composite field object
+ # don't have any effect on the parent.
+ #
+ # (NOTE that when we clear the composite field in the parent, we actually
+ # don't recursively clear down the tree. Instead, we just disconnect the
+ # cleared composite from the tree.)
+ self.assertTrue(old_composite_field is not composite_field)
+ setattr(old_composite_field, scalar_field_name, new_val)
+ self.assertTrue(not composite_field.HasField(scalar_field_name))
+ self.assertTrue(not 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 testReferencesToNestedMessage(self):
+ proto = unittest_pb2.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 testDisconnectingNestedMessageBeforeSettingField(self):
+ proto = unittest_pb2.TestAllTypes()
+ nested = proto.optional_nested_message
+ proto.ClearField('optional_nested_message') # Should disconnect from parent
+ self.assertTrue(nested is not proto.optional_nested_message)
+ nested.bb = 23
+ self.assertTrue(not proto.HasField('optional_nested_message'))
+ self.assertEqual(0, proto.optional_nested_message.bb)
+
+ 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.assertTrue(not 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.assertTrue(not recursive_proto.HasField('bb'))
+ self.assertEqual(0, recursive_proto.bb.a.bb.a.bb.optional_int32)
+ self.assertTrue(not 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.assertTrue(not recursive_proto.bb.a.bb.a.bb.HasField('a'))
+ self.assertTrue(recursive_proto.bb.a.bb.a.bb.HasField('optional_int32'))
+
+ def testSingularListFields(self):
+ proto = unittest_pb2.TestAllTypes()
+ proto.optional_fixed32 = 1
+ proto.optional_int32 = 5
+ proto.optional_string = 'foo'
+ 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())
+
+ def testRepeatedListFields(self):
+ proto = unittest_pb2.TestAllTypes()
+ proto.repeated_fixed32.append(1)
+ proto.repeated_int32.append(5)
+ proto.repeated_int32.append(11)
+ proto.repeated_string.append('foo')
+ proto.repeated_string.append('bar')
+ proto.repeated_string.append('baz')
+ proto.optional_int32 = 21
+ 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']) ],
+ proto.ListFields())
+
+ 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())
+
+ 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())
+
+ 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('', 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('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)
+
+ def testHasFieldWithUnknownFieldName(self):
+ proto = unittest_pb2.TestAllTypes()
+ self.assertRaises(ValueError, proto.HasField, 'nonexistent_field')
+
+ def testClearFieldWithUnknownFieldName(self):
+ proto = unittest_pb2.TestAllTypes()
+ self.assertRaises(ValueError, proto.ClearField, 'nonexistent_field')
+
+ def testDisallowedAssignments(self):
+ # It's illegal to assign values directly to repeated fields
+ # or to nonrepeated composite fields. Ensure that this fails.
+ proto = unittest_pb2.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)
+ # proto.nonexistent_field = 23 should fail as well.
+ self.assertRaises(AttributeError, setattr, proto, 'nonexistent_field', 23)
+
+ # TODO(robinson): Add type-safety check for enums.
+ def testSingleScalarTypeSafety(self):
+ proto = unittest_pb2.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)
+
+ def testSingleScalarBoundsChecking(self):
+ def TestMinAndMaxIntegers(field_name, expected_min, expected_max):
+ pb = unittest_pb2.TestAllTypes()
+ setattr(pb, field_name, expected_min)
+ setattr(pb, field_name, expected_max)
+ self.assertRaises(ValueError, setattr, pb, field_name, expected_min - 1)
+ self.assertRaises(ValueError, 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)
+ TestMinAndMaxIntegers('optional_nested_enum', -(1 << 31), (1 << 31) - 1)
+
+ def testRepeatedScalarTypeSafety(self):
+ proto = unittest_pb2.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')
+
+ def testSingleScalarGettersAndSetters(self):
+ proto = unittest_pb2.TestAllTypes()
+ self.assertEqual(0, proto.optional_int32)
+ proto.optional_int32 = 1
+ self.assertEqual(1, proto.optional_int32)
+ # TODO(robinson): Test all other scalar field types.
+
+ 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.assertTrue(not proto.HasField('optional_int32'))
+ # TODO(robinson): Test all other scalar field types.
+
+ def testEnums(self):
+ 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 testRepeatedScalars(self):
+ proto = unittest_pb2.TestAllTypes()
+
+ self.assertTrue(not proto.repeated_int32)
+ self.assertEqual(0, len(proto.repeated_int32))
+ proto.repeated_int32.append(5);
+ proto.repeated_int32.append(10);
+ self.assertTrue(proto.repeated_int32)
+ self.assertEqual(2, len(proto.repeated_int32))
+
+ self.assertEqual([5, 10], proto.repeated_int32)
+ self.assertEqual(5, proto.repeated_int32[0])
+ self.assertEqual(10, 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 that we can use the field as an iterator.
+ result = []
+ for i in proto.repeated_int32:
+ result.append(i)
+ self.assertEqual([5, 10], result)
+
+ # Test clearing.
+ proto.ClearField('repeated_int32')
+ self.assertTrue(not proto.repeated_int32)
+ self.assertEqual(0, len(proto.repeated_int32))
+
+ def testRepeatedComposites(self):
+ proto = unittest_pb2.TestAllTypes()
+ self.assertTrue(not 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.assertTrue(m0 is proto.repeated_nested_message[0])
+ self.assertTrue(m1 is proto.repeated_nested_message[1])
+ self.assertTrue(isinstance(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 that we can use the field as an iterator.
+ result = []
+ for i in proto.repeated_nested_message:
+ result.append(i)
+ self.assertEqual(2, len(result))
+ self.assertTrue(m0 is result[0])
+ self.assertTrue(m1 is result[1])
+
+ # Test clearing.
+ proto.ClearField('repeated_nested_message')
+ self.assertTrue(not proto.repeated_nested_message)
+ self.assertEqual(0, len(proto.repeated_nested_message))
+
+ def testHandWrittenReflection(self):
+ # TODO(robinson): We probably need a better way to specify
+ # protocol types by hand. But then again, this isn't something
+ # we expect many people to do. Hmm.
+ 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())
+ 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())
+ class MyProtoClass(message.Message):
+ DESCRIPTOR = mydescriptor
+ __metaclass__ = reflection.GeneratedProtocolMessageType
+ myproto_instance = MyProtoClass()
+ self.assertEqual(0, myproto_instance.foo_field)
+ self.assertTrue(not myproto_instance.HasField('foo_field'))
+ myproto_instance.foo_field = 23
+ self.assertEqual(23, myproto_instance.foo_field)
+ self.assertTrue(myproto_instance.HasField('foo_field'))
+
+ def testTopLevelExtensionsForOptionalScalar(self):
+ extendee_proto = unittest_pb2.TestAllExtensions()
+ extension = unittest_pb2.optional_int32_extension
+ self.assertTrue(not extendee_proto.HasExtension(extension))
+ self.assertEqual(0, extendee_proto.Extensions[extension])
+ # As with normal scalar fields, just doing a read doesn't actually set the
+ # "has" bit.
+ self.assertTrue(not extendee_proto.HasExtension(extension))
+ # Actually set the thing.
+ extendee_proto.Extensions[extension] = 23
+ self.assertEqual(23, extendee_proto.Extensions[extension])
+ self.assertTrue(extendee_proto.HasExtension(extension))
+ # Ensure that clearing works as well.
+ extendee_proto.ClearExtension(extension)
+ self.assertEqual(0, extendee_proto.Extensions[extension])
+ self.assertTrue(not extendee_proto.HasExtension(extension))
+
+ def testTopLevelExtensionsForRepeatedScalar(self):
+ extendee_proto = unittest_pb2.TestAllExtensions()
+ extension = unittest_pb2.repeated_string_extension
+ self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+ extendee_proto.Extensions[extension].append('foo')
+ self.assertEqual(['foo'], extendee_proto.Extensions[extension])
+ string_list = extendee_proto.Extensions[extension]
+ extendee_proto.ClearExtension(extension)
+ self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+ self.assertTrue(string_list is not 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.assertTrue(not extendee_proto.HasExtension(extension))
+ 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.assertTrue(not extendee_proto.HasExtension(extension))
+ extendee_proto.Extensions[extension].c = 23
+ self.assertEqual(23, extendee_proto.Extensions[extension].c)
+ self.assertTrue(extendee_proto.HasExtension(extension))
+ # Save a reference here.
+ foreign_message = extendee_proto.Extensions[extension]
+ extendee_proto.ClearExtension(extension)
+ self.assertTrue(foreign_message is not 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.assertTrue(not extendee_proto.HasExtension(extension))
+ # 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.assertTrue(group_list is not 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.assertTrue(not extendee_proto.HasExtension(extension))
+ required = extendee_proto.Extensions[extension]
+ self.assertEqual(0, required.a)
+ self.assertTrue(not extendee_proto.HasExtension(extension))
+ required.a = 23
+ self.assertEqual(23, extendee_proto.Extensions[extension].a)
+ self.assertTrue(extendee_proto.HasExtension(extension))
+ extendee_proto.ClearExtension(extension)
+ self.assertTrue(required is not extendee_proto.Extensions[extension])
+ self.assertTrue(not extendee_proto.HasExtension(extension))
+
+ # 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.assertTrue(not toplevel.HasField('submessage'))
+ self.assertEqual(0, toplevel.submessage.Extensions[
+ more_extensions_pb2.optional_int_extension])
+ self.assertTrue(not 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.assertTrue(not toplevel.HasField('submessage'))
+ self.assertEqual([], toplevel.submessage.Extensions[
+ more_extensions_pb2.repeated_int_extension])
+ self.assertTrue(not 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.assertTrue(not toplevel.HasField('submessage'))
+ self.assertEqual(0, toplevel.submessage.Extensions[
+ more_extensions_pb2.optional_message_extension].foreign_message_int)
+ self.assertTrue(not 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.assertTrue(not toplevel.HasField('submessage'))
+ self.assertEqual(0, len(toplevel.submessage.Extensions[
+ more_extensions_pb2.repeated_message_extension]))
+ self.assertTrue(not toplevel.HasField('submessage'))
+ foreign = toplevel.submessage.Extensions[
+ more_extensions_pb2.repeated_message_extension].add()
+ self.assertTrue(foreign is 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.assertTrue(not toplevel.HasField('submessage'))
+ self.assertTrue(extension_proto is not 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...
+ unknown_handle = more_extensions_pb2.optional_int_extension
+ self.assertRaises(KeyError, extendee_proto.HasExtension,
+ unknown_handle)
+ self.assertRaises(KeyError, extendee_proto.ClearExtension,
+ unknown_handle)
+ self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__,
+ unknown_handle)
+ self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__,
+ unknown_handle, 5)
+
+ # 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 testCopyFrom(self):
+ # TODO(robinson): Implement.
+ pass
+
+ def testClear(self):
+ proto = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(proto)
+ # Clear the message.
+ proto.Clear()
+ self.assertEquals(proto.ByteSize(), 0)
+ empty_proto = unittest_pb2.TestAllTypes()
+ self.assertEquals(proto, empty_proto)
+
+ # Test if extensions which were set are cleared.
+ proto = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(proto)
+ # Clear the message.
+ proto.Clear()
+ self.assertEquals(proto.ByteSize(), 0)
+ empty_proto = unittest_pb2.TestAllExtensions()
+ self.assertEquals(proto, empty_proto)
+
+ def testIsInitialized(self):
+ # Trivial cases - all optional fields and extensions.
+ proto = unittest_pb2.TestAllTypes()
+ self.assertTrue(proto.IsInitialized())
+ proto = unittest_pb2.TestAllExtensions()
+ self.assertTrue(proto.IsInitialized())
+
+ # The case of uninitialized required fields.
+ proto = unittest_pb2.TestRequired()
+ self.assertFalse(proto.IsInitialized())
+ proto.a = proto.b = proto.c = 2
+ self.assertTrue(proto.IsInitialized())
+
+ # The case of uninitialized submessage.
+ proto = unittest_pb2.TestRequiredForeign()
+ self.assertTrue(proto.IsInitialized())
+ proto.optional_message.a = 1
+ self.assertFalse(proto.IsInitialized())
+ proto.optional_message.b = 0
+ proto.optional_message.c = 0
+ self.assertTrue(proto.IsInitialized())
+
+ # Uninitialized repeated submessage.
+ message1 = proto.repeated_message.add()
+ self.assertFalse(proto.IsInitialized())
+ message1.a = message1.b = message1.c = 0
+ self.assertTrue(proto.IsInitialized())
+
+ # 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.assertFalse(proto.IsInitialized())
+ message1.a = 1
+ message1.b = 1
+ message1.c = 1
+ self.assertFalse(proto.IsInitialized())
+ message2.a = 2
+ message2.b = 2
+ message2.c = 2
+ self.assertTrue(proto.IsInitialized())
+
+ # Uninitialized nonrepeated message in an extension.
+ proto = unittest_pb2.TestAllExtensions()
+ extension = unittest_pb2.TestRequired.single
+ proto.Extensions[extension].a = 1
+ self.assertFalse(proto.IsInitialized())
+ proto.Extensions[extension].b = 2
+ proto.Extensions[extension].c = 3
+ self.assertTrue(proto.IsInitialized())
+
+
+# Since we had so many tests for protocol buffer equality, we broke these out
+# into separate TestCase classes.
+
+
+class TestAllTypesEqualityTest(unittest.TestCase):
+
+ def setUp(self):
+ self.first_proto = unittest_pb2.TestAllTypes()
+ self.second_proto = unittest_pb2.TestAllTypes()
+
+ def testSelfEquality(self):
+ self.assertEqual(self.first_proto, self.first_proto)
+
+ def testEmptyProtosEqual(self):
+ self.assertEqual(self.first_proto, self.second_proto)
+
+
+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 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)
+ # TODO(robinson): Replace next two lines with method
+ # to set the "has" bit without changing the value,
+ # if/when such a method exists.
+ self.first_proto.optional_nested_message.bb = 0
+ self.first_proto.optional_nested_message.ClearField('bb')
+ self.assertEqual(self.first_proto, self.second_proto)
+
+
+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)
+
+
+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)
+
+
+class ByteSizeTest(unittest.TestCase):
+
+ def setUp(self):
+ self.proto = unittest_pb2.TestAllTypes()
+ self.extended_proto = more_extensions_pb2.ExtendedMessage()
+
+ def Size(self):
+ return self.proto.ByteSize()
+
+ def testEmptyMessage(self):
+ self.assertEqual(0, self.proto.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 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 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())
+
+ 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())
+ 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())
+
+
+# TODO(robinson): We need cross-language serialization consistency tests.
+# 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).
+
+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))
+ 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))
+ 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()
+ second_proto.MergeFromString(serialized)
+ self.assertEqual(first_proto, second_proto)
+
+ 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 = decoder.Decoder(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
+
+ second_proto.MergeFromString(serialized)
+ # 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 = unittest_mset_pb2.TestMessageSet()
+ extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
+ extension_message2 = unittest_mset_pb2.TestMessageSetExtension2
+ extension1 = extension_message1.message_set_extension
+ extension2 = extension_message2.message_set_extension
+ proto.Extensions[extension1].i = 123
+ proto.Extensions[extension2].str = 'foo'
+
+ # 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)
+ raw.MergeFromString(serialized)
+ self.assertEqual(2, len(raw.item))
+
+ message1 = unittest_mset_pb2.TestMessageSetExtension1()
+ message1.MergeFromString(raw.item[0].message)
+ self.assertEqual(123, message1.i)
+
+ message2 = unittest_mset_pb2.TestMessageSetExtension2()
+ message2.MergeFromString(raw.item[1].message)
+ self.assertEqual('foo', message2.str)
+
+ # Deserialize using the MessageSet wire format.
+ proto2 = unittest_mset_pb2.TestMessageSet()
+ proto2.MergeFromString(serialized)
+ self.assertEqual(123, proto2.Extensions[extension1].i)
+ self.assertEqual('foo', proto2.Extensions[extension2].str)
+
+ # 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 = 1545008
+ extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
+ message1 = unittest_mset_pb2.TestMessageSetExtension1()
+ message1.i = 12345
+ item.message = message1.SerializeToString()
+
+ # Add a second, unknown extension.
+ item = raw.item.add()
+ item.type_id = 1545009
+ extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
+ message1 = unittest_mset_pb2.TestMessageSetExtension1()
+ message1.i = 12346
+ item.message = message1.SerializeToString()
+
+ # Add another unknown extension.
+ item = raw.item.add()
+ item.type_id = 1545010
+ message1 = unittest_mset_pb2.TestMessageSetExtension2()
+ message1.str = 'foo'
+ item.message = message1.SerializeToString()
+
+ serialized = raw.SerializeToString()
+
+ # Parse message using the message set wire format.
+ proto = unittest_mset_pb2.TestMessageSet()
+ proto.MergeFromString(serialized)
+
+ # Check that the message parsed well.
+ extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
+ extension1 = extension_message1.message_set_extension
+ self.assertEquals(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.
+ proto2.MergeFromString(serialized)
+
+
+class OptionsTest(unittest.TestCase):
+
+ def testMessageOptions(self):
+ proto = unittest_mset_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)
+
+
+class UtilityTest(unittest.TestCase):
+
+ def testImergeSorted(self):
+ ImergeSorted = reflection._ImergeSorted
+ # Various types of emptiness.
+ self.assertEqual([], list(ImergeSorted()))
+ self.assertEqual([], list(ImergeSorted([])))
+ self.assertEqual([], list(ImergeSorted([], [])))
+
+ # One nonempty list.
+ self.assertEqual([1, 2, 3], list(ImergeSorted([1, 2, 3])))
+ self.assertEqual([1, 2, 3], list(ImergeSorted([1, 2, 3], [])))
+ self.assertEqual([1, 2, 3], list(ImergeSorted([], [1, 2, 3])))
+
+ # Merging some nonempty lists together.
+ self.assertEqual([1, 2, 3], list(ImergeSorted([1, 3], [2])))
+ self.assertEqual([1, 2, 3], list(ImergeSorted([1], [3], [2])))
+ self.assertEqual([1, 2, 3], list(ImergeSorted([1], [3], [2], [])))
+
+ # Elements repeated across component iterators.
+ self.assertEqual([1, 2, 2, 3, 3],
+ list(ImergeSorted([1, 2], [3], [2, 3])))
+
+ # Elements repeated within an iterator.
+ self.assertEqual([1, 2, 2, 3, 3],
+ list(ImergeSorted([1, 2, 2], [3], [3])))
+
+
+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 100755
index 00000000..895d24d3
--- /dev/null
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -0,0 +1,98 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""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.DESCRIPTOR
+ srvc.CallMethod(service_descriptor.methods[1], rpc_controller,
+ unittest_pb2.BarRequest(), MyCallback)
+ self.assertEqual('Method Bar not implemented.',
+ rpc_controller.failure_message)
+ self.assertEqual(None, self.callback_response)
+
+ 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'
+
+ # Invoke method.
+ stub.Foo(rpc_controller, request, MyCallback)
+
+ self.assertTrue(isinstance(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/test_util.py b/python/google/protobuf/internal/test_util.py
new file mode 100755
index 00000000..d9106421
--- /dev/null
+++ b/python/google/protobuf/internal/test_util.py
@@ -0,0 +1,354 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Utilities for Python proto2 tests.
+
+This is intentionally modeled on C++ code in
+//net/proto2/internal/test_util.*.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import os.path
+
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_pb2
+
+
+def SetAllFields(message):
+ """Sets every field in the message to a unique value.
+
+ Args:
+ message: A unittest_pb2.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
+ # TODO(robinson): Firmly spec out and test how
+ # protos interact with unicode. One specific example:
+ # what happens if we change the literal below to
+ # u'115'? What *should* happen? Still some discussion
+ # to finish with Kenton about bytes vs. strings
+ # and forcing everything to be utf8. :-/
+ message.optional_string = '115'
+ message.optional_bytes = '116'
+
+ message.optionalgroup.a = 117
+ message.optional_nested_message.bb = 118
+ message.optional_foreign_message.c = 119
+ message.optional_import_message.d = 120
+
+ message.optional_nested_enum = unittest_pb2.TestAllTypes.BAZ
+ message.optional_foreign_enum = unittest_pb2.FOREIGN_BAZ
+ message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
+
+ message.optional_string_piece = '124'
+ message.optional_cord = '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('215')
+ message.repeated_bytes.append('216')
+
+ 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_nested_enum.append(unittest_pb2.TestAllTypes.BAR)
+ message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
+ message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
+
+ message.repeated_string_piece.append('224')
+ message.repeated_cord.append('225')
+
+ # Add a second one of each field.
+ message.repeated_int32.append(301)
+ message.repeated_int64.append(302)
+ message.repeated_uint32.append(303)
+ message.repeated_uint64.append(304)
+ message.repeated_sint32.append(305)
+ message.repeated_sint64.append(306)
+ message.repeated_fixed32.append(307)
+ message.repeated_fixed64.append(308)
+ message.repeated_sfixed32.append(309)
+ message.repeated_sfixed64.append(310)
+ message.repeated_float.append(311)
+ message.repeated_double.append(312)
+ message.repeated_bool.append(False)
+ message.repeated_string.append('315')
+ message.repeated_bytes.append('316')
+
+ 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_nested_enum.append(unittest_pb2.TestAllTypes.BAZ)
+ message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
+ message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
+
+ message.repeated_string_piece.append('324')
+ message.repeated_cord.append('325')
+
+ #
+ # Fields that have defaults.
+ #
+
+ message.default_int32 = 401
+ message.default_int64 = 402
+ message.default_uint32 = 403
+ message.default_uint64 = 404
+ message.default_sint32 = 405
+ message.default_sint64 = 406
+ message.default_fixed32 = 407
+ message.default_fixed64 = 408
+ message.default_sfixed32 = 409
+ message.default_sfixed64 = 410
+ message.default_float = 411
+ message.default_double = 412
+ message.default_bool = False
+ message.default_string = '415'
+ message.default_bytes = '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'
+
+
+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] = '115'
+ extensions[pb2.optional_bytes_extension] = '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_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] = '124'
+ extensions[pb2.optional_cord_extension] = '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('215')
+ extensions[pb2.repeated_bytes_extension].append('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_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('224')
+ extensions[pb2.repeated_cord_extension].append('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('315')
+ extensions[pb2.repeated_bytes_extension].append('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_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('324')
+ extensions[pb2.repeated_cord_extension].append('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] = '415'
+ extensions[pb2.default_bytes_extension] = '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] = '424'
+ extensions[pb2.default_cord_extension] = '425'
+
+
+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 = ''.join(expected_strings)
+
+ if expected != serialized:
+ raise ValueError('Expected %r, found %r' % (expected, serialized))
+
+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.
+ return file(os.path.join(path, 'src/google/protobuf/testdata', filename))
+ path = os.path.join(path, '..')
+
+ 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.')
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
new file mode 100755
index 00000000..c2074db5
--- /dev/null
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -0,0 +1,97 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Test for google.protobuf.text_format."""
+
+__author__ = 'kenton@google.com (Kenton Varda)'
+
+import difflib
+
+import unittest
+from google.protobuf import text_format
+from google.protobuf.internal import test_util
+from google.protobuf import unittest_pb2
+from google.protobuf import unittest_mset_pb2
+
+class TextFormatTest(unittest.TestCase):
+ def CompareToGoldenFile(self, text, golden_filename):
+ f = test_util.GoldenFile(golden_filename)
+ golden_lines = f.readlines()
+ f.close()
+ self.CompareToGoldenLines(text, golden_lines)
+
+ def CompareToGoldenText(self, text, golden_text):
+ self.CompareToGoldenLines(text, golden_text.splitlines(1))
+
+ def CompareToGoldenLines(self, text, golden_lines):
+ actual_lines = text.splitlines(1)
+ self.assertEqual(golden_lines, actual_lines,
+ "Text doesn't match golden. Diff:\n" +
+ ''.join(difflib.ndiff(golden_lines, actual_lines)))
+
+ def testPrintAllFields(self):
+ message = unittest_pb2.TestAllTypes()
+ test_util.SetAllFields(message)
+ self.CompareToGoldenFile(text_format.MessageToString(message),
+ 'text_format_unittest_data.txt')
+
+ def testPrintAllExtensions(self):
+ message = unittest_pb2.TestAllExtensions()
+ test_util.SetAllExtensions(message)
+ self.CompareToGoldenFile(text_format.MessageToString(message),
+ 'text_format_unittest_extensions_data.txt')
+
+ def testPrintMessageSet(self):
+ message = unittest_mset_pb2.TestMessageSetContainer()
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+ message.message_set.Extensions[ext1].i = 23
+ message.message_set.Extensions[ext2].str = 'foo'
+ self.CompareToGoldenText(text_format.MessageToString(message),
+ 'message_set {\n'
+ ' [protobuf_unittest.TestMessageSetExtension1] {\n'
+ ' i: 23\n'
+ ' }\n'
+ ' [protobuf_unittest.TestMessageSetExtension2] {\n'
+ ' str: \"foo\"\n'
+ ' }\n'
+ '}\n')
+
+ def testPrintExotic(self):
+ message = unittest_pb2.TestAllTypes()
+ 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\\\'\"');
+ self.CompareToGoldenText(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')
+
+ def testMessageToString(self):
+ message = unittest_pb2.ForeignMessage()
+ message.c = 123
+ self.assertEqual('c: 123\n', str(message))
+
+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 100755
index 00000000..69aa4abf
--- /dev/null
+++ b/python/google/protobuf/internal/wire_format.py
@@ -0,0 +1,222 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Constants and static functions to support protocol buffer wire format."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+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 //net/proto2/public/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'
+
+
+# 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)) | 0x1
+
+
+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 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 (_TagByteSize(field_number)
+ + _VarUInt64ByteSizeNoTag(len(string))
+ + len(string))
+
+
+def BytesByteSize(field_number, b):
+ return StringByteSize(field_number, 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
+
+
+# Private helper functions for the *ByteSize() functions above.
+
+
+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))
+
+
+def _VarUInt64ByteSizeNoTag(uint64):
+ """Returns the bytes required to serialize a single varint.
+ uint64 must be unsigned.
+ """
+ if uint64 > UINT64_MAX:
+ raise message.EncodeError('Value out of range: %d' % uint64)
+ bytes = 1
+ while uint64 > 0x7f:
+ bytes += 1
+ uint64 >>= 7
+ return bytes
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
new file mode 100755
index 00000000..87e0ddf5
--- /dev/null
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -0,0 +1,232 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""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))
+
+ 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/message.py b/python/google/protobuf/message.py
new file mode 100755
index 00000000..9b48f889
--- /dev/null
+++ b/python/google/protobuf/message.py
@@ -0,0 +1,184 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+# 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)'
+
+from google.protobuf import text_format
+
+class Error(Exception): pass
+class DecodeError(Error): pass
+class EncodeError(Error): 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__ = []
+
+ DESCRIPTOR = None
+
+ def __eq__(self, other_msg):
+ 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 __str__(self):
+ return text_format.MessageToString(self)
+
+ def MergeFrom(self, other_msg):
+ raise NotImplementedError
+
+ def CopyFrom(self, other_msg):
+ raise NotImplementedError
+
+ def Clear(self):
+ raise NotImplementedError
+
+ def IsInitialized(self):
+ 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.
+
+ TODO(robinson): Document handling of unknown fields.
+
+ Args:
+ serialized: Any object that allows us to call buffer(serialized)
+ to access a string of bytes using the buffer interface.
+
+ TODO(robinson): When we switch to a helper, this will return None.
+
+ Returns:
+ 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.
+ """
+ raise NotImplementedError
+
+ def ParseFromString(self, serialized):
+ """Like MergeFromString(), except we clear the object first."""
+ self.Clear()
+ self.MergeFromString(serialized)
+
+ def SerializeToString(self):
+ 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, field_name):
+ """Returns a list of (FieldDescriptor, value) tuples for all
+ fields in the message which are not empty. A singular field is non-empty
+ if HasField() would return true, and a repeated field is non-empty if
+ it contains at least one element. The fields are ordered by field
+ number"""
+ raise NotImplementedError
+
+ def HasField(self, field_name):
+ raise NotImplementedError
+
+ def ClearField(self, field_name):
+ raise NotImplementedError
+
+ def HasExtension(self, extension_handle):
+ raise NotImplementedError
+
+ def ClearExtension(self, extension_handle):
+ raise NotImplementedError
+
+ def ByteSize(self):
+ """Returns the serialized size of this message.
+ Recursively calls ByteSize() on all contained messages.
+ """
+ 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
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
new file mode 100755
index 00000000..75202c4e
--- /dev/null
+++ b/python/google/protobuf/reflection.py
@@ -0,0 +1,1734 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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 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)'
+
+import heapq
+import threading
+import weakref
+# We use "as" to avoid name collisions with variables.
+from google.protobuf.internal import decoder
+from google.protobuf.internal import encoder
+from google.protobuf.internal import message_listener as message_listener_mod
+from google.protobuf.internal import wire_format
+from google.protobuf import descriptor as descriptor_mod
+from google.protobuf import message as message_mod
+
+_FieldDescriptor = descriptor_mod.FieldDescriptor
+
+
+class GeneratedProtocolMessageType(type):
+
+ """Metaclass for protocol message classes created at runtime from Descriptors.
+
+ We add implementations for all methods described in the Message class. We
+ also create properties to allow getting/setting all fields in the protocol
+ message. Finally, we create slots to prevent users from accidentally
+ "setting" nonexistent fields in the protocol message, which then wouldn't get
+ serialized / deserialized properly.
+
+ The protocol compiler currently uses this metaclass to create protocol
+ message classes at runtime. Clients can also manually create their own
+ classes at runtime, as in this example:
+
+ mydescriptor = Descriptor(.....)
+ class MyProtoClass(Message):
+ __metaclass__ = GeneratedProtocolMessageType
+ DESCRIPTOR = mydescriptor
+ myproto_instance = MyProtoClass()
+ myproto.foo_field = 23
+ ...
+ """
+
+ # Must be consistent with the protocol-compiler code in
+ # proto2/compiler/internal/generator.*.
+ _DESCRIPTOR_KEY = 'DESCRIPTOR'
+
+ def __new__(cls, name, bases, dictionary):
+ """Custom allocation for runtime-generated class types.
+
+ We override __new__ because this is apparently the only place
+ where we can meaningfully set __slots__ on the class we're creating(?).
+ (The interplay between metaclasses and slots is not very well-documented).
+
+ Args:
+ name: Name of the class (ignored, but required by the
+ metaclass protocol).
+ bases: Base classes of the class we're constructing.
+ (Should be message.Message). We ignore this field, but
+ it's required by the metaclass protocol
+ dictionary: The class dictionary of the class we're
+ constructing. dictionary[_DESCRIPTOR_KEY] must contain
+ a Descriptor object describing this protocol message
+ type.
+
+ Returns:
+ Newly-allocated class.
+ """
+ descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+ _AddSlots(descriptor, dictionary)
+ _AddClassAttributesForNestedExtensions(descriptor, dictionary)
+ superclass = super(GeneratedProtocolMessageType, cls)
+ return superclass.__new__(cls, name, bases, dictionary)
+
+ 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]
+ # We act as a "friend" class of the descriptor, setting
+ # its _concrete_class attribute the first time we use a
+ # given descriptor to initialize a concrete protocol message
+ # class.
+ concrete_class_attr_name = '_concrete_class'
+ if not hasattr(descriptor, concrete_class_attr_name):
+ setattr(descriptor, concrete_class_attr_name, cls)
+ cls._known_extensions = []
+ _AddEnumValues(descriptor, cls)
+ _AddInitMethod(descriptor, cls)
+ _AddPropertiesForFields(descriptor, cls)
+ _AddStaticMethods(cls)
+ _AddMessageMethods(descriptor, cls)
+ _AddPrivateHelperMethods(cls)
+ superclass = super(GeneratedProtocolMessageType, cls)
+ superclass.__init__(cls, 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
+ # """
+ return proto_field_name
+
+
+def _ValueFieldName(proto_field_name):
+ """Returns the name of the (internal) instance attribute which objects
+ should use to store the current value for a given protocol message field.
+
+ Args:
+ proto_field_name: The protocol message field name, exactly
+ as it appears (or would appear) in a .proto file.
+ """
+ return '_value_' + proto_field_name
+
+
+def _HasFieldName(proto_field_name):
+ """Returns the name of the (internal) instance attribute which
+ objects should use to store a boolean telling whether this field
+ is explicitly set or not.
+
+ Args:
+ proto_field_name: The protocol message field name, exactly
+ as it appears (or would appear) in a .proto file.
+ """
+ return '_has_' + 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.
+ """
+ field_names = [_ValueFieldName(f.name) for f in message_descriptor.fields]
+ field_names.extend(_HasFieldName(f.name) for f in message_descriptor.fields
+ if f.label != _FieldDescriptor.LABEL_REPEATED)
+ field_names.extend(('Extensions',
+ '_cached_byte_size',
+ '_cached_byte_size_dirty',
+ '_called_transition_to_nonempty',
+ '_listener',
+ '_lock', '__weakref__'))
+ dictionary['__slots__'] = field_names
+
+
+def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
+ extension_dict = descriptor.extensions_by_name
+ for extension_name, extension_field in extension_dict.iteritems():
+ assert extension_name not in dictionary
+ dictionary[extension_name] = extension_field
+
+
+def _AddEnumValues(descriptor, cls):
+ """Sets class-level attributes for all enum fields defined in this message.
+
+ Args:
+ descriptor: Descriptor object for this message type.
+ cls: Class we're constructing for this message type.
+ """
+ for enum_type in descriptor.enum_types:
+ for enum_value in enum_type.values:
+ setattr(cls, enum_value.name, enum_value.number)
+
+
+def _DefaultValueForField(message, field):
+ """Returns a default value for a field.
+
+ Args:
+ message: Message instance containing this field, or a weakref proxy
+ of same.
+ field: FieldDescriptor object for this field.
+
+ Returns: A default value for this field. May refer back to |message|
+ via a weak reference.
+ """
+ # TODO(robinson): Only the repeated fields need a reference to 'message' (so
+ # that they can set the 'has' bit on the containing Message when someone
+ # append()s a value). We could special-case this, and avoid an extra
+ # function call on __init__() and Clear() for non-repeated fields.
+
+ # TODO(robinson): Find a better place for the default value assertion in this
+ # function. No need to repeat them every time the client calls Clear('foo').
+ # (We should probably just assert these things once and as early as possible,
+ # by tightening checking in the descriptor classes.)
+ if field.label == _FieldDescriptor.LABEL_REPEATED:
+ if field.default_value != []:
+ raise ValueError('Repeated field default value not empty list: %s' % (
+ field.default_value))
+ listener = _Listener(message, None)
+ 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).
+ return _RepeatedCompositeFieldContainer(listener, field.message_type)
+ else:
+ return _RepeatedScalarFieldContainer(listener,
+ _VALUE_CHECKERS[field.cpp_type])
+
+ if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+ assert field.default_value is None
+
+ return field.default_value
+
+
+def _AddInitMethod(message_descriptor, cls):
+ """Adds an __init__ method to cls."""
+ fields = message_descriptor.fields
+ def init(self):
+ self._cached_byte_size = 0
+ self._cached_byte_size_dirty = False
+ self._listener = message_listener_mod.NullMessageListener()
+ self._called_transition_to_nonempty = False
+ # TODO(robinson): We should only create a lock if we really need one
+ # in this class.
+ self._lock = threading.Lock()
+ for field in fields:
+ default_value = _DefaultValueForField(self, field)
+ python_field_name = _ValueFieldName(field.name)
+ setattr(self, python_field_name, default_value)
+ if field.label != _FieldDescriptor.LABEL_REPEATED:
+ setattr(self, _HasFieldName(field.name), False)
+ self.Extensions = _ExtensionDict(self, cls._known_extensions)
+
+ init.__module__ = None
+ init.__doc__ = None
+ cls.__init__ = init
+
+
+def _AddPropertiesForFields(descriptor, cls):
+ """Adds properties for all fields in this protocol message type."""
+ for field in descriptor.fields:
+ _AddPropertiesForField(field, cls)
+
+
+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
+
+ if field.label == _FieldDescriptor.LABEL_REPEATED:
+ _AddPropertiesForRepeatedField(field, cls)
+ elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+ _AddPropertiesForNonRepeatedCompositeField(field, cls)
+ else:
+ _AddPropertiesForNonRepeatedScalarField(field, cls)
+
+
+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
+ python_field_name = _ValueFieldName(proto_field_name)
+ property_name = _PropertyName(proto_field_name)
+
+ def getter(self):
+ return getattr(self, python_field_name)
+ 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, property(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
+ python_field_name = _ValueFieldName(proto_field_name)
+ has_field_name = _HasFieldName(proto_field_name)
+ property_name = _PropertyName(proto_field_name)
+ type_checker = _VALUE_CHECKERS[field.cpp_type]
+
+ def getter(self):
+ return getattr(self, python_field_name)
+ getter.__module__ = None
+ getter.__doc__ = 'Getter for %s.' % proto_field_name
+ def setter(self, new_value):
+ type_checker.CheckValue(new_value)
+ setattr(self, has_field_name, True)
+ self._MarkByteSizeDirty()
+ self._MaybeCallTransitionToNonemptyCallback()
+ setattr(self, python_field_name, new_value)
+ 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, property(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
+ python_field_name = _ValueFieldName(proto_field_name)
+ has_field_name = _HasFieldName(proto_field_name)
+ property_name = _PropertyName(proto_field_name)
+ message_type = field.message_type
+
+ def getter(self):
+ # TODO(robinson): Appropriately scary note about double-checked locking.
+ field_value = getattr(self, python_field_name)
+ if field_value is None:
+ self._lock.acquire()
+ try:
+ field_value = getattr(self, python_field_name)
+ if field_value is None:
+ field_class = message_type._concrete_class
+ field_value = field_class()
+ field_value._SetListener(_Listener(self, has_field_name))
+ setattr(self, python_field_name, field_value)
+ finally:
+ self._lock.release()
+ 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, property(getter, setter, doc=doc))
+
+
+def _AddStaticMethods(cls):
+ # TODO(robinson): This probably needs to be thread-safe(?)
+ def RegisterExtension(extension_handle):
+ extension_handle.containing_type = cls.DESCRIPTOR
+ cls._known_extensions.append(extension_handle)
+ cls.RegisterExtension = staticmethod(RegisterExtension)
+
+
+def _AddListFieldsMethod(message_descriptor, cls):
+ """Helper for _AddMessageMethods()."""
+
+ # Ensure that we always list in ascending field-number order.
+ # For non-extension fields, we can do the sort once, here, at import-time.
+ # For extensions, we sort on each ListFields() call, though
+ # we could do better if we have to.
+ fields = sorted(message_descriptor.fields, key=lambda f: f.number)
+ has_field_names = (_HasFieldName(f.name) for f in fields)
+ value_field_names = (_ValueFieldName(f.name) for f in fields)
+ triplets = zip(has_field_names, value_field_names, fields)
+
+ def ListFields(self):
+ # We need to list all extension and non-extension fields
+ # together, in sorted order by field number.
+
+ # Step 0: Get an iterator over all "set" non-extension fields,
+ # sorted by field number.
+ # This iterator yields (field_number, field_descriptor, value) tuples.
+ def SortedSetFieldsIter():
+ # Note that triplets is already sorted by field number.
+ for has_field_name, value_field_name, field_descriptor in triplets:
+ if field_descriptor.label == _FieldDescriptor.LABEL_REPEATED:
+ value = getattr(self, _ValueFieldName(field_descriptor.name))
+ if len(value) > 0:
+ yield (field_descriptor.number, field_descriptor, value)
+ elif getattr(self, _HasFieldName(field_descriptor.name)):
+ value = getattr(self, _ValueFieldName(field_descriptor.name))
+ yield (field_descriptor.number, field_descriptor, value)
+ sorted_fields = SortedSetFieldsIter()
+
+ # Step 1: Get an iterator over all "set" extension fields,
+ # sorted by field number.
+ # This iterator ALSO yields (field_number, field_descriptor, value) tuples.
+ # TODO(robinson): It's not necessary to repeat this with each
+ # serialization call. We can do better.
+ sorted_extension_fields = sorted(
+ [(f.number, f, v) for f, v in self.Extensions._ListSetExtensions()])
+
+ # Step 2: Create a composite iterator that merges the extension-
+ # and non-extension fields, and that still yields fields in
+ # sorted order.
+ all_set_fields = _ImergeSorted(sorted_fields, sorted_extension_fields)
+
+ # Step 3: Strip off the field numbers and return.
+ return [field[1:] for field in all_set_fields]
+
+ cls.ListFields = ListFields
+
+def _AddHasFieldMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def HasField(self, field_name):
+ try:
+ return getattr(self, _HasFieldName(field_name))
+ except AttributeError:
+ raise ValueError('Protocol message has no "%s" field.' % field_name)
+ cls.HasField = HasField
+
+
+def _AddClearFieldMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def ClearField(self, field_name):
+ try:
+ field = self.DESCRIPTOR.fields_by_name[field_name]
+ except KeyError:
+ raise ValueError('Protocol message has no "%s" field.' % field_name)
+ proto_field_name = field.name
+ python_field_name = _ValueFieldName(proto_field_name)
+ has_field_name = _HasFieldName(proto_field_name)
+ default_value = _DefaultValueForField(self, field)
+ if field.label == _FieldDescriptor.LABEL_REPEATED:
+ self._MarkByteSizeDirty()
+ else:
+ if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+ old_field_value = getattr(self, python_field_name)
+ if old_field_value is not None:
+ # Snip the old object out of the object tree.
+ old_field_value._SetListener(None)
+ if getattr(self, has_field_name):
+ setattr(self, has_field_name, False)
+ # Set dirty bit on ourself and parents only if
+ # we're actually changing state.
+ self._MarkByteSizeDirty()
+ setattr(self, python_field_name, default_value)
+ cls.ClearField = ClearField
+
+
+def _AddClearExtensionMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def ClearExtension(self, extension_handle):
+ self.Extensions._ClearExtension(extension_handle)
+ cls.ClearExtension = ClearExtension
+
+
+def _AddClearMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def Clear(self):
+ # Clear fields.
+ fields = self.DESCRIPTOR.fields
+ for field in fields:
+ self.ClearField(field.name)
+ # Clear extensions.
+ extensions = self.Extensions._ListSetExtensions()
+ for extension in extensions:
+ self.ClearExtension(extension[0])
+ cls.Clear = Clear
+
+
+def _AddHasExtensionMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def HasExtension(self, extension_handle):
+ return self.Extensions._HasExtension(extension_handle)
+ cls.HasExtension = HasExtension
+
+
+def _AddEqualsMethod(message_descriptor, cls):
+ """Helper for _AddMessageMethods()."""
+ def __eq__(self, other):
+ if self is other:
+ return True
+
+ # Compare all fields contained directly in this message.
+ for field_descriptor in message_descriptor.fields:
+ label = field_descriptor.label
+ property_name = _PropertyName(field_descriptor.name)
+ # Non-repeated field equality requires matching "has" bits as well
+ # as having an equal value.
+ if label != _FieldDescriptor.LABEL_REPEATED:
+ self_has = self.HasField(property_name)
+ other_has = other.HasField(property_name)
+ if self_has != other_has:
+ return False
+ if not self_has:
+ # If the "has" bit for this field is False, we must stop here.
+ # Otherwise we will recurse forever on recursively-defined protos.
+ continue
+ if getattr(self, property_name) != getattr(other, property_name):
+ return False
+
+ # Compare the extensions present in both messages.
+ return self.Extensions == other.Extensions
+ cls.__eq__ = __eq__
+
+
+def _AddSetListenerMethod(cls):
+ """Helper for _AddMessageMethods()."""
+ def SetListener(self, listener):
+ if listener is None:
+ self._listener = message_listener_mod.NullMessageListener()
+ else:
+ self._listener = listener
+ cls._SetListener = SetListener
+
+
+def _BytesForNonRepeatedElement(value, field_number, field_type):
+ """Returns the number of bytes needed to serialize a non-repeated element.
+ The returned byte count includes space for tag information and any
+ 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_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 BytesForField(message, field, value):
+ """Returns the number of bytes required to serialize a single field
+ in message. The field may be repeated or not, composite or not.
+
+ Args:
+ message: The Message instance containing a field of the given type.
+ field: A FieldDescriptor describing the field of interest.
+ value: The value whose byte size we're interested in.
+
+ Returns: The number of bytes required to serialize the current value
+ of "field" in "message", including space for tags and any other
+ necessary information.
+ """
+
+ if _MessageSetField(field):
+ return wire_format.MessageSetItemByteSize(field.number, value)
+
+ field_number, field_type = field.number, field.type
+
+ # Repeated fields.
+ if field.label == _FieldDescriptor.LABEL_REPEATED:
+ elements = value
+ else:
+ elements = [value]
+
+ size = sum(_BytesForNonRepeatedElement(element, field_number, field_type)
+ for element in elements)
+ return size
+
+ fields = message_descriptor.fields
+ has_field_names = (_HasFieldName(f.name) for f in fields)
+ zipped = zip(has_field_names, fields)
+
+ def ByteSize(self):
+ if not self._cached_byte_size_dirty:
+ return self._cached_byte_size
+
+ size = 0
+ # Hardcoded fields first.
+ for has_field_name, field in zipped:
+ if (field.label == _FieldDescriptor.LABEL_REPEATED
+ or getattr(self, has_field_name)):
+ value = getattr(self, _ValueFieldName(field.name))
+ size += BytesForField(self, field, value)
+ # Extensions next.
+ for field, value in self.Extensions._ListSetExtensions():
+ size += BytesForField(self, field, value)
+
+ self._cached_byte_size = size
+ self._cached_byte_size_dirty = False
+ return size
+ cls.ByteSize = ByteSize
+
+
+def _MessageSetField(field_descriptor):
+ """Checks if a field should be serialized using the message set wire format.
+
+ Args:
+ field_descriptor: Descriptor of the field.
+
+ Returns:
+ True if the field should be serialized using the message set wire format,
+ false otherwise.
+ """
+ return (field_descriptor.is_extension and
+ field_descriptor.label != _FieldDescriptor.LABEL_REPEATED and
+ field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
+ field_descriptor.containing_type.GetOptions().message_set_wire_format)
+
+
+def _SerializeValueToEncoder(value, field_number, field_descriptor, encoder):
+ """Appends the serialization of a single value to encoder.
+
+ Args:
+ value: Value to serialize.
+ field_number: Field number of this value.
+ field_descriptor: Descriptor of the field to serialize.
+ encoder: encoder.Encoder object to which we should serialize this value.
+ """
+ if _MessageSetField(field_descriptor):
+ encoder.AppendMessageSetItem(field_number, value)
+ return
+
+ try:
+ method = _TYPE_TO_SERIALIZE_METHOD[field_descriptor.type]
+ method(encoder, field_number, value)
+ except KeyError:
+ raise message_mod.EncodeError('Unrecognized field type: %d' %
+ field_descriptor.type)
+
+
+def _ImergeSorted(*streams):
+ """Merges N sorted iterators into a single sorted iterator.
+ Each element in streams must be an iterable that yields
+ its elements in sorted order, and the elements contained
+ in each stream must all be comparable.
+
+ There may be repeated elements in the component streams or
+ across the streams; the repeated elements will all be repeated
+ in the merged iterator as well.
+
+ I believe that the heapq module at HEAD in the Python
+ sources has a method like this, but for now we roll our own.
+ """
+ iters = [iter(stream) for stream in streams]
+ heap = []
+ for index, it in enumerate(iters):
+ try:
+ heap.append((it.next(), index))
+ except StopIteration:
+ pass
+ heapq.heapify(heap)
+
+ while heap:
+ smallest_value, idx = heap[0]
+ yield smallest_value
+ try:
+ next_element = iters[idx].next()
+ heapq.heapreplace(heap, (next_element, idx))
+ except StopIteration:
+ heapq.heappop(heap)
+
+
+def _AddSerializeToStringMethod(message_descriptor, cls):
+ """Helper for _AddMessageMethods()."""
+ Encoder = encoder.Encoder
+
+ def SerializeToString(self):
+ encoder = Encoder()
+ # We need to serialize all extension and non-extension fields
+ # together, in sorted order by field number.
+
+ # Step 3: Iterate over all extension and non-extension fields, sorted
+ # in order of tag number, and serialize each one to the wire.
+ for field_descriptor, field_value in self.ListFields():
+ if field_descriptor.label == _FieldDescriptor.LABEL_REPEATED:
+ repeated_value = field_value
+ else:
+ repeated_value = [field_value]
+ for element in repeated_value:
+ _SerializeValueToEncoder(element, field_descriptor.number,
+ field_descriptor, encoder)
+ return encoder.ToString()
+ cls.SerializeToString = SerializeToString
+
+
+def _WireTypeForFieldType(field_type):
+ """Given a field type, returns the expected wire type."""
+ try:
+ return _FIELD_TYPE_TO_WIRE_TYPE[field_type]
+ except KeyError:
+ raise message_mod.DecodeError('Unknown field type: %d' % field_type)
+
+
+def _RecursivelyMerge(field_number, field_type, decoder, message):
+ """Decodes a message from decoder into message.
+ message is either a group or a nested message within some containing
+ protocol message. If it's a group, we use the group protocol to
+ deserialize, and if it's a nested message, we use the nested-message
+ protocol.
+
+ Args:
+ field_number: The field number of message in its enclosing protocol buffer.
+ field_type: The field type of message. Must be either TYPE_MESSAGE
+ or TYPE_GROUP.
+ decoder: Decoder to read from.
+ message: Message to deserialize into.
+ """
+ if field_type == _FieldDescriptor.TYPE_MESSAGE:
+ decoder.ReadMessageInto(message)
+ elif field_type == _FieldDescriptor.TYPE_GROUP:
+ decoder.ReadGroupInto(field_number, message)
+ else:
+ raise message_mod.DecodeError('Unexpected field type: %d' % field_type)
+
+
+def _DeserializeScalarFromDecoder(field_type, decoder):
+ """Deserializes a scalar of the requested type from decoder. field_type must
+ be a scalar (non-group, non-message) FieldDescriptor.FIELD_* constant.
+ """
+ try:
+ method = _TYPE_TO_DESERIALIZE_METHOD[field_type]
+ return method(decoder)
+ except KeyError:
+ raise message_mod.DecodeError('Unrecognized field type: %d' % field_type)
+
+
+def _SkipField(field_number, wire_type, decoder):
+ """Skips a field with the specified wire type.
+
+ Args:
+ field_number: Tag number of the field to skip.
+ wire_type: Wire type of the field to skip.
+ decoder: Decoder used to deserialize the messsage. It must be positioned
+ just after reading the the tag and wire type of the field.
+ """
+ if wire_type == wire_format.WIRETYPE_VARINT:
+ decoder.ReadInt32()
+ elif wire_type == wire_format.WIRETYPE_FIXED64:
+ decoder.ReadFixed64()
+ elif wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED:
+ decoder.SkipBytes(decoder.ReadInt32())
+ elif wire_type == wire_format.WIRETYPE_START_GROUP:
+ _SkipGroup(field_number, decoder)
+ elif wire_type == wire_format.WIRETYPE_END_GROUP:
+ pass
+ elif wire_type == wire_format.WIRETYPE_FIXED32:
+ decoder.ReadFixed32()
+ else:
+ raise message_mod.DecodeError('Unexpected wire type: %d' % wire_type)
+
+
+def _SkipGroup(group_number, decoder):
+ """Skips a nested group from the decoder.
+
+ Args:
+ group_number: Tag number of the group to skip.
+ decoder: Decoder used to deserialize the message. It must be positioned
+ exactly at the beginning of the message that should be skipped.
+ """
+ while True:
+ field_number, wire_type = decoder.ReadFieldNumberAndWireType()
+ if (wire_type == wire_format.WIRETYPE_END_GROUP and
+ field_number == group_number):
+ return
+ _SkipField(field_number, wire_type, decoder)
+
+
+def _DeserializeMessageSetItem(message, decoder):
+ """Deserializes a message using the message set wire format.
+
+ Args:
+ message: Message to be parsed to.
+ decoder: The decoder to be used to deserialize encoded data. Note that the
+ decoder should be positioned just after reading the START_GROUP tag that
+ began the messageset item.
+ """
+ field_number, wire_type = decoder.ReadFieldNumberAndWireType()
+ if wire_type != wire_format.WIRETYPE_VARINT or field_number != 2:
+ raise message_mod.DecodeError(
+ 'Incorrect message set wire format. '
+ 'wire_type: %d, field_number: %d' % (wire_type, field_number))
+
+ type_id = decoder.ReadInt32()
+ field_number, wire_type = decoder.ReadFieldNumberAndWireType()
+ if wire_type != wire_format.WIRETYPE_LENGTH_DELIMITED or field_number != 3:
+ raise message_mod.DecodeError(
+ 'Incorrect message set wire format. '
+ 'wire_type: %d, field_number: %d' % (wire_type, field_number))
+
+ extension_dict = message.Extensions
+ extensions_by_number = extension_dict._AllExtensionsByNumber()
+ if type_id not in extensions_by_number:
+ _SkipField(field_number, wire_type, decoder)
+ return
+
+ field_descriptor = extensions_by_number[type_id]
+ value = extension_dict[field_descriptor]
+ decoder.ReadMessageInto(value)
+ # Read the END_GROUP tag.
+ field_number, wire_type = decoder.ReadFieldNumberAndWireType()
+ if wire_type != wire_format.WIRETYPE_END_GROUP or field_number != 1:
+ raise message_mod.DecodeError(
+ 'Incorrect message set wire format. '
+ 'wire_type: %d, field_number: %d' % (wire_type, field_number))
+
+
+def _DeserializeOneEntity(message_descriptor, message, decoder):
+ """Deserializes the next wire entity from decoder into message.
+ The next wire entity is either a scalar or a nested message,
+ and may also be an element in a repeated field (the wire encoding
+ is the same).
+
+ Args:
+ message_descriptor: A Descriptor instance describing all fields
+ in message.
+ message: The Message instance into which we're decoding our fields.
+ decoder: The Decoder we're using to deserialize encoded data.
+
+ Returns: The number of bytes read from decoder during this method.
+ """
+ initial_position = decoder.Position()
+ field_number, wire_type = decoder.ReadFieldNumberAndWireType()
+ extension_dict = message.Extensions
+ extensions_by_number = extension_dict._AllExtensionsByNumber()
+ if field_number in message_descriptor.fields_by_number:
+ # Non-extension field.
+ field_descriptor = message_descriptor.fields_by_number[field_number]
+ value = getattr(message, _PropertyName(field_descriptor.name))
+ def nonextension_setter_fn(scalar):
+ setattr(message, _PropertyName(field_descriptor.name), scalar)
+ scalar_setter_fn = nonextension_setter_fn
+ elif field_number in extensions_by_number:
+ # Extension field.
+ field_descriptor = extensions_by_number[field_number]
+ value = extension_dict[field_descriptor]
+ def extension_setter_fn(scalar):
+ extension_dict[field_descriptor] = scalar
+ scalar_setter_fn = extension_setter_fn
+ elif wire_type == wire_format.WIRETYPE_END_GROUP:
+ # We assume we're being parsed as the group that's ended.
+ return 0
+ elif (wire_type == wire_format.WIRETYPE_START_GROUP and
+ field_number == 1 and
+ message_descriptor.GetOptions().message_set_wire_format):
+ # A Message Set item.
+ _DeserializeMessageSetItem(message, decoder)
+ return decoder.Position() - initial_position
+ else:
+ _SkipField(field_number, wire_type, decoder)
+ return decoder.Position() - initial_position
+
+ # If we reach this point, we've identified the field as either
+ # hardcoded or extension, and set |field_descriptor|, |scalar_setter_fn|,
+ # and |value| appropriately. Now actually deserialize the thing.
+ #
+ # field_descriptor: Describes the field we're deserializing.
+ # value: The value currently stored in the field to deserialize.
+ # Used only if the field is composite and/or repeated.
+ # scalar_setter_fn: A function F such that F(scalar) will
+ # set a nonrepeated scalar value for this field. Used only
+ # if this field is a nonrepeated scalar.
+
+ field_number = field_descriptor.number
+ field_type = field_descriptor.type
+ expected_wire_type = _WireTypeForFieldType(field_type)
+ if wire_type != expected_wire_type:
+ # Need to fill in uninterpreted_bytes. Work for the next CL.
+ raise RuntimeError('TODO(robinson): Wiretype mismatches not handled.')
+
+ property_name = _PropertyName(field_descriptor.name)
+ label = field_descriptor.label
+ cpp_type = field_descriptor.cpp_type
+
+ # Nonrepeated scalar. Just set the field directly.
+ if (label != _FieldDescriptor.LABEL_REPEATED
+ and cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE):
+ scalar_setter_fn(_DeserializeScalarFromDecoder(field_type, decoder))
+ return decoder.Position() - initial_position
+
+ # Nonrepeated composite. Recursively deserialize.
+ if label != _FieldDescriptor.LABEL_REPEATED:
+ composite = value
+ _RecursivelyMerge(field_number, field_type, decoder, composite)
+ return decoder.Position() - initial_position
+
+ # Now we know we're dealing with a repeated field of some kind.
+ element_list = value
+
+ if cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE:
+ # Repeated scalar.
+ element_list.append(_DeserializeScalarFromDecoder(field_type, decoder))
+ return decoder.Position() - initial_position
+ else:
+ # Repeated composite.
+ composite = element_list.add()
+ _RecursivelyMerge(field_number, field_type, decoder, composite)
+ return decoder.Position() - initial_position
+
+
+def _FieldOrExtensionValues(message, field_or_extension):
+ """Retrieves the list of values for the specified field or extension.
+
+ The target field or extension can be optional, required or repeated, but it
+ must have value(s) set. The assumption is that the target field or extension
+ is set (e.g. _HasFieldOrExtension holds true).
+
+ Args:
+ message: Message which contains the target field or extension.
+ field_or_extension: Field or extension for which the list of values is
+ required. Must be an instance of FieldDescriptor.
+
+ Returns:
+ A list of values for the specified field or extension. This list will only
+ contain a single element if the field is non-repeated.
+ """
+ if field_or_extension.is_extension:
+ value = message.Extensions[field_or_extension]
+ else:
+ value = getattr(message, _ValueFieldName(field_or_extension.name))
+ if field_or_extension.label != _FieldDescriptor.LABEL_REPEATED:
+ return [value]
+ else:
+ # In this case value is a list or repeated values.
+ return value
+
+
+def _HasFieldOrExtension(message, field_or_extension):
+ """Checks if a message has the specified field or extension set.
+
+ The field or extension specified can be optional, required or repeated. If
+ it is repeated, this function returns True. Otherwise it checks the has bit
+ of the field or extension.
+
+ Args:
+ message: Message which contains the target field or extension.
+ field_or_extension: Field or extension to check. This must be a
+ FieldDescriptor instance.
+
+ Returns:
+ True if the message has a value set for the specified field or extension,
+ or if the field or extension is repeated.
+ """
+ if field_or_extension.label == _FieldDescriptor.LABEL_REPEATED:
+ return True
+ if field_or_extension.is_extension:
+ return message.HasExtension(field_or_extension)
+ else:
+ return message.HasField(field_or_extension.name)
+
+
+def _IsFieldOrExtensionInitialized(message, field):
+ """Checks if a message field or extension is initialized.
+
+ Args:
+ message: The message which contains the field or extension.
+ field: Field or extension to check. This must be a FieldDescriptor instance.
+
+ Returns:
+ True if the field/extension can be considered initialized.
+ """
+ # If the field is required and is not set, it isn't initialized.
+ if field.label == _FieldDescriptor.LABEL_REQUIRED:
+ if not _HasFieldOrExtension(message, field):
+ return False
+
+ # If the field is optional and is not set, or if it
+ # isn't a submessage then the field is initialized.
+ if field.label == _FieldDescriptor.LABEL_OPTIONAL:
+ if not _HasFieldOrExtension(message, field):
+ return True
+ if field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE:
+ return True
+
+ # The field is set and is either a single or a repeated submessage.
+ messages = _FieldOrExtensionValues(message, field)
+ # If all submessages in this field are initialized, the field is
+ # considered initialized.
+ for message in messages:
+ if not message.IsInitialized():
+ return False
+ return True
+
+
+def _AddMergeFromStringMethod(message_descriptor, cls):
+ """Helper for _AddMessageMethods()."""
+ Decoder = decoder.Decoder
+ def MergeFromString(self, serialized):
+ decoder = Decoder(serialized)
+ byte_count = 0
+ while not decoder.EndOfStream():
+ bytes_read = _DeserializeOneEntity(message_descriptor, self, decoder)
+ if not bytes_read:
+ break
+ byte_count += bytes_read
+ return byte_count
+ cls.MergeFromString = MergeFromString
+
+
+def _AddIsInitializedMethod(message_descriptor, cls):
+ """Adds the IsInitialized method to the protocol message class."""
+ def IsInitialized(self):
+ fields_and_extensions = []
+ fields_and_extensions.extend(message_descriptor.fields)
+ fields_and_extensions.extend(
+ self.Extensions._AllExtensionsByNumber().values())
+ for field_or_extension in fields_and_extensions:
+ if not _IsFieldOrExtensionInitialized(self, field_or_extension):
+ return False
+ return True
+ cls.IsInitialized = IsInitialized
+
+
+def _AddMessageMethods(message_descriptor, cls):
+ """Adds implementations of all Message methods to cls."""
+
+ # TODO(robinson): Add support for remaining Message methods.
+
+ _AddListFieldsMethod(message_descriptor, cls)
+ _AddHasFieldMethod(cls)
+ _AddClearFieldMethod(cls)
+ _AddClearExtensionMethod(cls)
+ _AddClearMethod(cls)
+ _AddHasExtensionMethod(cls)
+ _AddEqualsMethod(message_descriptor, cls)
+ _AddSetListenerMethod(cls)
+ _AddByteSizeMethod(message_descriptor, cls)
+ _AddSerializeToStringMethod(message_descriptor, cls)
+ _AddMergeFromStringMethod(message_descriptor, cls)
+ _AddIsInitializedMethod(message_descriptor, cls)
+
+
+def _AddPrivateHelperMethods(cls):
+ """Adds implementation of private helper methods to cls."""
+
+ def MaybeCallTransitionToNonemptyCallback(self):
+ """Calls self._listener.TransitionToNonempty() the first time this
+ method is called. On all subsequent calls, this is a no-op.
+ """
+ if not self._called_transition_to_nonempty:
+ self._listener.TransitionToNonempty()
+ self._called_transition_to_nonempty = True
+ cls._MaybeCallTransitionToNonemptyCallback = (
+ MaybeCallTransitionToNonemptyCallback)
+
+ def MarkByteSizeDirty(self):
+ """Sets the _cached_byte_size_dirty bit to true,
+ and propagates this to our listener iff this was a state change.
+ """
+ if not self._cached_byte_size_dirty:
+ self._cached_byte_size_dirty = True
+ self._listener.ByteSizeDirty()
+ cls._MarkByteSizeDirty = MarkByteSizeDirty
+
+
+class _Listener(object):
+
+ """MessageListener implementation that a parent message registers with its
+ child message.
+
+ In order to support semantics like:
+
+ foo.bar.baz = 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, has_field_name):
+ """Args:
+ parent_message: The message whose _MaybeCallTransitionToNonemptyCallback()
+ and _MarkByteSizeDirty() methods we should call when we receive
+ TransitionToNonempty() and ByteSizeDirty() messages.
+ has_field_name: The name of the "has" field that we should set in
+ the parent message when we receive a TransitionToNonempty message,
+ or None if there's no "has" field to set. (This will be the case
+ for child objects in "repeated" fields).
+ """
+ # 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)
+ self._has_field_name = has_field_name
+
+ def TransitionToNonempty(self):
+ try:
+ if self._has_field_name is not None:
+ setattr(self._parent_message_weakref, self._has_field_name, True)
+ # Propagate the signal to our parents iff this is the first field set.
+ self._parent_message_weakref._MaybeCallTransitionToNonemptyCallback()
+ 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
+
+ def ByteSizeDirty(self):
+ try:
+ self._parent_message_weakref._MarkByteSizeDirty()
+ except ReferenceError:
+ # Same as above.
+ pass
+
+
+# TODO(robinson): Move elsewhere?
+# TODO(robinson): Provide a clear() method here in addition to ClearField()?
+class _RepeatedScalarFieldContainer(object):
+
+ """Simple, type-checked, list-like container for holding repeated scalars.
+ """
+
+ def __init__(self, message_listener, type_checker):
+ """
+ Args:
+ message_listener: A MessageListener implementation.
+ The _RepeatedScalarFieldContaininer will call this object's
+ TransitionToNonempty() method when it transitions from being empty to
+ being nonempty.
+ type_checker: A _ValueChecker instance to run on elements inserted
+ into this container.
+ """
+ self._message_listener = message_listener
+ self._type_checker = type_checker
+ self._values = []
+
+ def append(self, elem):
+ self._type_checker.CheckValue(elem)
+ self._values.append(elem)
+ self._message_listener.ByteSizeDirty()
+ if len(self._values) == 1:
+ self._message_listener.TransitionToNonempty()
+
+ # List-like __getitem__() support also makes us iterable (via "iter(foo)"
+ # or implicitly via "for i in mylist:") for free.
+ def __getitem__(self, key):
+ return self._values[key]
+
+ def __setitem__(self, key, value):
+ # No need to call TransitionToNonempty(), since if we're able to
+ # set the element at this index, we were already nonempty before
+ # this method was called.
+ self._message_listener.ByteSizeDirty()
+ self._type_checker.CheckValue(value)
+ self._values[key] = value
+
+ def __len__(self):
+ return len(self._values)
+
+ def __eq__(self, other):
+ 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 __ne__(self, other):
+ # Can't use != here since it would infinitely recurse.
+ return not self == other
+
+
+# TODO(robinson): Move elsewhere?
+# TODO(robinson): Provide a clear() method here in addition to ClearField()?
+# TODO(robinson): Unify common functionality with
+# _RepeatedScalarFieldContaininer?
+class _RepeatedCompositeFieldContainer(object):
+
+ """Simple, list-like container for holding repeated composite fields.
+ """
+
+ def __init__(self, message_listener, message_descriptor):
+ """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
+ TransitionToNonempty() method when it transitions from being empty to
+ being nonempty.
+ 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().
+ """
+ self._message_listener = message_listener
+ self._message_descriptor = message_descriptor
+ self._values = []
+
+ def add(self):
+ new_element = self._message_descriptor._concrete_class()
+ new_element._SetListener(self._message_listener)
+ self._values.append(new_element)
+ self._message_listener.ByteSizeDirty()
+ self._message_listener.TransitionToNonempty()
+ return new_element
+
+ # List-like __getitem__() support also makes us iterable (via "iter(foo)"
+ # or implicitly via "for i in mylist:") for free.
+ def __getitem__(self, key):
+ return self._values[key]
+
+ def __len__(self):
+ return len(self._values)
+
+ def __eq__(self, other):
+ 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
+
+ def __ne__(self, other):
+ # Can't use != here since it would infinitely recurse.
+ return not self == other
+
+ # TODO(robinson): Implement, document, and test slicing support.
+
+
+# TODO(robinson): Move elsewhere? This file is getting pretty ridiculous...
+# TODO(robinson): Unify error handling of "unknown extension" crap.
+# TODO(robinson): There's so much similarity between the way that
+# extensions behave and the way that normal fields behave that it would
+# be really nice to unify more code. It's not immediately obvious
+# how to do this, though, and I'd rather get the full functionality
+# implemented (and, crucially, get all the tests and specs fleshed out
+# and passing), and then come back to this thorny unification problem.
+# TODO(robinson): Support iteritems()-style iteration over all
+# extensions with the "has" bits turned on?
+class _ExtensionDict(object):
+
+ """Dict-like container for supporting an indexable "Extensions"
+ field on proto instances.
+
+ Note that in all cases we expect extension handles to be
+ FieldDescriptors.
+ """
+
+ class _ExtensionListener(object):
+
+ """Adapts an _ExtensionDict to behave as a MessageListener."""
+
+ def __init__(self, extension_dict, handle_id):
+ self._extension_dict = extension_dict
+ self._handle_id = handle_id
+
+ def TransitionToNonempty(self):
+ self._extension_dict._SubmessageTransitionedToNonempty(self._handle_id)
+
+ def ByteSizeDirty(self):
+ self._extension_dict._SubmessageByteSizeBecameDirty()
+
+ # TODO(robinson): Somewhere, we need to blow up if people
+ # try to register two extensions with the same field number.
+ # (And we need a test for this of course).
+
+ def __init__(self, extended_message, known_extensions):
+ """extended_message: Message instance for which we are the Extensions dict.
+ known_extensions: Iterable of known extension handles.
+ These must be FieldDescriptors.
+ """
+ # We keep a weak reference to extended_message, since
+ # it has a reference to this instance in turn.
+ self._extended_message = weakref.proxy(extended_message)
+ # We make a deep copy of known_extensions to avoid any
+ # thread-safety concerns, since the argument passed in
+ # is the global (class-level) dict of known extensions for
+ # this type of message, which could be modified at any time
+ # via a RegisterExtension() call.
+ #
+ # This dict maps from handle id to handle (a FieldDescriptor).
+ #
+ # XXX
+ # TODO(robinson): This isn't good enough. The client could
+ # instantiate an object in module A, then afterward import
+ # module B and pass the instance to B.Foo(). If B imports
+ # an extender of this proto and then tries to use it, B
+ # will get a KeyError, even though the extension *is* registered
+ # at the time of use.
+ # XXX
+ self._known_extensions = dict((id(e), e) for e in known_extensions)
+ # Read lock around self._values, which may be modified by multiple
+ # concurrent readers in the conceptually "const" __getitem__ method.
+ # So, we grab this lock in every "read-only" method to ensure
+ # that concurrent read access is safe without external locking.
+ self._lock = threading.Lock()
+ # Maps from extension handle ID to current value of that extension.
+ self._values = {}
+ # Maps from extension handle ID to a boolean "has" bit, but only
+ # for non-repeated extension fields.
+ keys = (id for id, extension in self._known_extensions.iteritems()
+ if extension.label != _FieldDescriptor.LABEL_REPEATED)
+ self._has_bits = dict.fromkeys(keys, False)
+
+ def __getitem__(self, extension_handle):
+ """Returns the current value of the given extension handle."""
+ # We don't care as much about keeping critical sections short in the
+ # extension support, since it's presumably much less of a common case.
+ self._lock.acquire()
+ try:
+ handle_id = id(extension_handle)
+ if handle_id not in self._known_extensions:
+ raise KeyError('Extension not known to this class')
+ if handle_id not in self._values:
+ self._AddMissingHandle(extension_handle, handle_id)
+ return self._values[handle_id]
+ finally:
+ self._lock.release()
+
+ def __eq__(self, other):
+ # We have to grab read locks since we're accessing _values
+ # in a "const" method. See the comment in the constructor.
+ if self is other:
+ return True
+ self._lock.acquire()
+ try:
+ other._lock.acquire()
+ try:
+ if self._has_bits != other._has_bits:
+ return False
+ # If there's a "has" bit, then only compare values where it is true.
+ for k, v in self._values.iteritems():
+ if self._has_bits.get(k, False) and v != other._values[k]:
+ return False
+ return True
+ finally:
+ other._lock.release()
+ finally:
+ self._lock.release()
+
+ def __ne__(self, other):
+ return not self == other
+
+ # Note that this is only meaningful for non-repeated, scalar extension
+ # fields. Note also that we may have to call
+ # MaybeCallTransitionToNonemptyCallback() when we do successfully set a field
+ # this way, to set any necssary "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.
+ """
+ handle_id = id(extension_handle)
+ if handle_id not in self._known_extensions:
+ raise KeyError('Extension not known to this class')
+ field = extension_handle # Just shorten the name.
+ if (field.label == _FieldDescriptor.LABEL_OPTIONAL
+ and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE):
+ # It's slightly wasteful to lookup the type checker each time,
+ # but we expect this to be a vanishingly uncommon case anyway.
+ type_checker = _VALUE_CHECKERS[field.cpp_type]
+ type_checker.CheckValue(value)
+ self._values[handle_id] = value
+ self._has_bits[handle_id] = True
+ self._extended_message._MarkByteSizeDirty()
+ self._extended_message._MaybeCallTransitionToNonemptyCallback()
+ else:
+ raise TypeError('Extension is repeated and/or a composite type.')
+
+ def _AddMissingHandle(self, extension_handle, handle_id):
+ """Helper internal to ExtensionDict."""
+ # Special handling for non-repeated message extensions, which (like
+ # normal fields of this kind) are initialized lazily.
+ # REQUIRES: _lock already held.
+ cpp_type = extension_handle.cpp_type
+ label = extension_handle.label
+ if (cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
+ and label != _FieldDescriptor.LABEL_REPEATED):
+ self._AddMissingNonRepeatedCompositeHandle(extension_handle, handle_id)
+ else:
+ self._values[handle_id] = _DefaultValueForField(
+ self._extended_message, extension_handle)
+
+ def _AddMissingNonRepeatedCompositeHandle(self, extension_handle, handle_id):
+ """Helper internal to ExtensionDict."""
+ # REQUIRES: _lock already held.
+ value = extension_handle.message_type._concrete_class()
+ value._SetListener(_ExtensionDict._ExtensionListener(self, handle_id))
+ self._values[handle_id] = value
+
+ def _SubmessageTransitionedToNonempty(self, handle_id):
+ """Called when a submessage with a given handle id first transitions to
+ being nonempty. Called by _ExtensionListener.
+ """
+ assert handle_id in self._has_bits
+ self._has_bits[handle_id] = True
+ self._extended_message._MaybeCallTransitionToNonemptyCallback()
+
+ def _SubmessageByteSizeBecameDirty(self):
+ """Called whenever a submessage's cached byte size becomes invalid
+ (goes from being "clean" to being "dirty"). Called by _ExtensionListener.
+ """
+ self._extended_message._MarkByteSizeDirty()
+
+ # We may wish to widen the public interface of Message.Extensions
+ # to expose some of this private functionality in the future.
+ # For now, we make all this functionality module-private and just
+ # implement what we need for serialization/deserialization,
+ # HasField()/ClearField(), etc.
+
+ def _HasExtension(self, extension_handle):
+ """Method for internal use by this module.
+ Returns true iff we "have" this extension in the sense of the
+ "has" bit being set.
+ """
+ handle_id = id(extension_handle)
+ # Note that this is different from the other checks.
+ if handle_id not in self._has_bits:
+ raise KeyError('Extension not known to this class, or is repeated field.')
+ return self._has_bits[handle_id]
+
+ # Intentionally pretty similar to ClearField() above.
+ def _ClearExtension(self, extension_handle):
+ """Method for internal use by this module.
+ Clears the specified extension, unsetting its "has" bit.
+ """
+ handle_id = id(extension_handle)
+ if handle_id not in self._known_extensions:
+ raise KeyError('Extension not known to this class')
+ default_value = _DefaultValueForField(self._extended_message,
+ extension_handle)
+ if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
+ self._extended_message._MarkByteSizeDirty()
+ else:
+ cpp_type = extension_handle.cpp_type
+ if cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+ if handle_id in self._values:
+ # Future modifications to this object shouldn't set any
+ # "has" bits here.
+ self._values[handle_id]._SetListener(None)
+ if self._has_bits[handle_id]:
+ self._has_bits[handle_id] = False
+ self._extended_message._MarkByteSizeDirty()
+ if handle_id in self._values:
+ del self._values[handle_id]
+
+ def _ListSetExtensions(self):
+ """Method for internal use by this module.
+
+ Returns an sequence of all extensions that are currently "set"
+ in this extension dict. A "set" extension is a repeated extension,
+ or a non-repeated extension with its "has" bit set.
+
+ The returned sequence contains (field_descriptor, value) pairs,
+ where value is the current value of the extension with the given
+ field descriptor.
+
+ The sequence values are in arbitrary order.
+ """
+ self._lock.acquire() # Read-only methods must lock around self._values.
+ try:
+ set_extensions = []
+ for handle_id, value in self._values.iteritems():
+ handle = self._known_extensions[handle_id]
+ if (handle.label == _FieldDescriptor.LABEL_REPEATED
+ or self._has_bits[handle_id]):
+ set_extensions.append((handle, value))
+ return set_extensions
+ finally:
+ self._lock.release()
+
+ def _AllExtensionsByNumber(self):
+ """Method for internal use by this module.
+
+ Returns: A dict mapping field_number to (handle, field_descriptor),
+ for *all* registered extensions for this dict.
+ """
+ # TODO(robinson): Precompute and store this away. Note that we'll have to
+ # be careful when we move away from having _known_extensions as a
+ # deep-copied member of this object.
+ return dict((f.number, f) for f in self._known_extensions.itervalues())
+
+
+# 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):
+ 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)
+
+
+# _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 isinstance(proposed_value, (int, long)):
+ message = ('%.1024r has type %s, but expected one of: %s' %
+ (proposed_value, type(proposed_value), (int, long)))
+ raise TypeError(message)
+ if not self._MIN <= proposed_value <= self._MAX:
+ raise ValueError('Value out of range: %d' % proposed_value)
+
+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
+
+
+# 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: _TypeChecker(
+ float, int, long),
+ _FieldDescriptor.CPPTYPE_FLOAT: _TypeChecker(
+ float, int, long),
+ _FieldDescriptor.CPPTYPE_BOOL: _TypeChecker(bool, int),
+ _FieldDescriptor.CPPTYPE_ENUM: _Int32ValueChecker(),
+ _FieldDescriptor.CPPTYPE_STRING: _TypeChecker(str),
+ }
+
+
+# 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 type to an unbound Encoder method F, such that
+# F(encoder, field_number, value) will append the serialization
+# of a value of this type to the encoder.
+_Encoder = encoder.Encoder
+_TYPE_TO_SERIALIZE_METHOD = {
+ _FieldDescriptor.TYPE_DOUBLE: _Encoder.AppendDouble,
+ _FieldDescriptor.TYPE_FLOAT: _Encoder.AppendFloat,
+ _FieldDescriptor.TYPE_INT64: _Encoder.AppendInt64,
+ _FieldDescriptor.TYPE_UINT64: _Encoder.AppendUInt64,
+ _FieldDescriptor.TYPE_INT32: _Encoder.AppendInt32,
+ _FieldDescriptor.TYPE_FIXED64: _Encoder.AppendFixed64,
+ _FieldDescriptor.TYPE_FIXED32: _Encoder.AppendFixed32,
+ _FieldDescriptor.TYPE_BOOL: _Encoder.AppendBool,
+ _FieldDescriptor.TYPE_STRING: _Encoder.AppendString,
+ _FieldDescriptor.TYPE_GROUP: _Encoder.AppendGroup,
+ _FieldDescriptor.TYPE_MESSAGE: _Encoder.AppendMessage,
+ _FieldDescriptor.TYPE_BYTES: _Encoder.AppendBytes,
+ _FieldDescriptor.TYPE_UINT32: _Encoder.AppendUInt32,
+ _FieldDescriptor.TYPE_ENUM: _Encoder.AppendEnum,
+ _FieldDescriptor.TYPE_SFIXED32: _Encoder.AppendSFixed32,
+ _FieldDescriptor.TYPE_SFIXED64: _Encoder.AppendSFixed64,
+ _FieldDescriptor.TYPE_SINT32: _Encoder.AppendSInt32,
+ _FieldDescriptor.TYPE_SINT64: _Encoder.AppendSInt64,
+ }
+
+# 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,
+ }
+
+# Maps from field type to an unbound Decoder method F,
+# such that F(decoder) will read a field of the requested type.
+#
+# Note that Message and Group are intentionally missing here.
+# They're handled by _RecursivelyMerge().
+_Decoder = decoder.Decoder
+_TYPE_TO_DESERIALIZE_METHOD = {
+ _FieldDescriptor.TYPE_DOUBLE: _Decoder.ReadDouble,
+ _FieldDescriptor.TYPE_FLOAT: _Decoder.ReadFloat,
+ _FieldDescriptor.TYPE_INT64: _Decoder.ReadInt64,
+ _FieldDescriptor.TYPE_UINT64: _Decoder.ReadUInt64,
+ _FieldDescriptor.TYPE_INT32: _Decoder.ReadInt32,
+ _FieldDescriptor.TYPE_FIXED64: _Decoder.ReadFixed64,
+ _FieldDescriptor.TYPE_FIXED32: _Decoder.ReadFixed32,
+ _FieldDescriptor.TYPE_BOOL: _Decoder.ReadBool,
+ _FieldDescriptor.TYPE_STRING: _Decoder.ReadString,
+ _FieldDescriptor.TYPE_BYTES: _Decoder.ReadBytes,
+ _FieldDescriptor.TYPE_UINT32: _Decoder.ReadUInt32,
+ _FieldDescriptor.TYPE_ENUM: _Decoder.ReadEnum,
+ _FieldDescriptor.TYPE_SFIXED32: _Decoder.ReadSFixed32,
+ _FieldDescriptor.TYPE_SFIXED64: _Decoder.ReadSFixed64,
+ _FieldDescriptor.TYPE_SINT32: _Decoder.ReadSInt32,
+ _FieldDescriptor.TYPE_SINT64: _Decoder.ReadSInt64,
+ }
diff --git a/python/google/protobuf/service.py b/python/google/protobuf/service.py
new file mode 100755
index 00000000..461031b7
--- /dev/null
+++ b/python/google/protobuf/service.py
@@ -0,0 +1,194 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Declares the RPC service interfaces.
+
+This module declares the abstract interfaces underlying proto2 RPC
+services. These are intented to be independent of any particular RPC
+implementation, so that proto2 services can be used on top of a variety
+of implementations.
+"""
+
+__author__ = 'petar@google.com (Petar Petrov)'
+
+
+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(self):
+ """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.
+
+ 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.
+ """
+ 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):
+
+ """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)
+ """
+
+ # 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):
+
+ """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).
+ """
+
+ 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 100755
index 00000000..6e3bf14e
--- /dev/null
+++ b/python/google/protobuf/service_reflection.py
@@ -0,0 +1,275 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""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)
+
+
+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(self, 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.
+ def _WrapCallMethod(srvc, method_descriptor,
+ rpc_controller, request, callback):
+ self._CallMethod(srvc, method_descriptor,
+ rpc_controller, request, callback)
+ self.cls = cls
+ cls.CallMethod = _WrapCallMethod
+ cls.GetDescriptor = self._GetDescriptor
+ cls.GetRequestClass = self._GetRequestClass
+ cls.GetResponseClass = self._GetResponseClass
+ for method in self.descriptor.methods:
+ setattr(cls, method.name, self._GenerateNonImplementedMethod(method))
+
+ def _GetDescriptor(self):
+ """Retrieves the service descriptor.
+
+ Returns:
+ The descriptor of the service (of type ServiceDescriptor).
+ """
+ return self.descriptor
+
+ 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(self.cls, method_descriptor.name)
+ method(srvc, 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: 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.
+ """
+ stub.rpc_channel.CallMethod(
+ method_descriptor, rpc_controller, request,
+ method_descriptor.output_type._concrete_class, callback)
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
new file mode 100755
index 00000000..428b4c0a
--- /dev/null
+++ b/python/google/protobuf/text_format.py
@@ -0,0 +1,111 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.
+# http://code.google.com/p/protobuf/
+#
+# 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.
+
+"""Contains routines for printing protocol messages in text format."""
+
+__author__ = 'kenton@google.com (Kenton Varda)'
+
+import cStringIO
+
+from google.protobuf import descriptor
+
+__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue' ]
+
+def MessageToString(message):
+ out = cStringIO.StringIO()
+ PrintMessage(message, out)
+ result = out.getvalue()
+ out.close()
+ return result
+
+def PrintMessage(message, out, indent = 0):
+ for field, value in message.ListFields():
+ if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ for element in value:
+ PrintField(field, element, out, indent)
+ else:
+ PrintField(field, value, out, indent)
+
+def PrintField(field, value, out, indent = 0):
+ """Print a single field name/value pair. For repeated fields, the value
+ should be a single element."""
+
+ out.write(' ' * indent);
+ if field.is_extension:
+ out.write('[')
+ if (field.containing_type.GetOptions().message_set_wire_format and
+ field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+ field.message_type == field.extension_scope and
+ field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
+ out.write(field.message_type.full_name)
+ else:
+ out.write(field.full_name)
+ out.write(']')
+ elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
+ # For groups, use the capitalized name.
+ out.write(field.message_type.name)
+ else:
+ out.write(field.name)
+
+ if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ # The colon is optional in this case, but our cross-language golden files
+ # don't include it.
+ out.write(': ')
+
+ PrintFieldValue(field, value, out, indent)
+ out.write('\n')
+
+def PrintFieldValue(field, value, out, indent = 0):
+ """Print a single field value (not including name). For repeated fields,
+ the value should be a single element."""
+
+ if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ out.write(' {\n')
+ PrintMessage(value, out, indent + 2)
+ out.write(' ' * indent + '}')
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+ out.write(field.enum_type.values_by_number[value].name)
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+ out.write('\"')
+ out.write(_CEscape(value))
+ out.write('\"')
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+ if value:
+ out.write("true")
+ else:
+ out.write("false")
+ else:
+ out.write(str(value))
+
+# text.encode('string_escape') does not seem to satisfy our needs as it
+# 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.
+def _CEscape(text):
+ def escape(c):
+ o = ord(c)
+ if o == 10: return r"\n" # optional escape
+ if o == 13: return r"\r" # optional escape
+ if o == 9: return r"\t" # optional escape
+ if o == 39: return r"\'" # optional escape
+
+ if o == 34: return r'\"' # necessary escape
+ if o == 92: return r"\\" # necessary escape
+
+ if o >= 127 or o < 32: return "\\%03o" % o # necessary escapes
+ return c
+ return "".join([escape(c) for c in text])
diff --git a/python/mox.py b/python/mox.py
new file mode 100755
index 00000000..ce80ba50
--- /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 occured. (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 mehtod 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/setup.py b/python/setup.py
new file mode 100755
index 00000000..eda25749
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,126 @@
+#! /usr/bin/python
+#
+# See README for usage instructions.
+
+# We must use setuptools, not distutils, because we need to use the
+# namespace_packages option for the "google" package.
+from ez_setup import use_setuptools
+use_setuptools()
+
+from setuptools import setup
+from distutils.spawn import find_executable
+import sys
+import os
+
+maintainer_email = "protobuf@googlegroups.com"
+
+# Find the Protocol Compiler.
+if os.path.exists("../src/protoc"):
+ protoc = "../src/protoc"
+else:
+ protoc = find_executable("protoc")
+
+def generate_proto(source):
+ """Invokes the Protocol Compiler to generate a _pb2.py from the given
+ .proto file. Does nothing if the output already exists and is newer than
+ the input."""
+
+ output = source.replace(".proto", "_pb2.py").replace("../src/", "")
+
+ if not os.path.exists(source):
+ print "Can't find required file: " + source
+ sys.exit(-1)
+
+ 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 protoc == 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 os.system(protoc_command) != 0:
+ sys.exit(-1)
+
+def MakeTestSuite():
+ generate_proto("../src/google/protobuf/unittest.proto")
+ generate_proto("../src/google/protobuf/unittest_import.proto")
+ generate_proto("../src/google/protobuf/unittest_mset.proto")
+ generate_proto("google/protobuf/internal/more_extensions.proto")
+ generate_proto("google/protobuf/internal/more_messages.proto")
+
+ import unittest
+ import google.protobuf.internal.generator_test as generator_test
+ import google.protobuf.internal.decoder_test as decoder_test
+ import google.protobuf.internal.descriptor_test as descriptor_test
+ import google.protobuf.internal.encoder_test as encoder_test
+ import google.protobuf.internal.input_stream_test as input_stream_test
+ import google.protobuf.internal.output_stream_test as output_stream_test
+ import google.protobuf.internal.reflection_test as reflection_test
+ import google.protobuf.internal.service_reflection_test \
+ as service_reflection_test
+ import google.protobuf.internal.text_format_test as text_format_test
+ import google.protobuf.internal.wire_format_test as wire_format_test
+
+ loader = unittest.defaultTestLoader
+ suite = unittest.TestSuite()
+ for test in [ generator_test,
+ decoder_test,
+ descriptor_test,
+ encoder_test,
+ input_stream_test,
+ output_stream_test,
+ reflection_test,
+ service_reflection_test,
+ text_format_test,
+ wire_format_test ]:
+ suite.addTest(loader.loadTestsFromModule(test))
+
+ return suite
+
+if __name__ == '__main__':
+ # TODO(kenton): Integrate this into setuptools somehow?
+ if len(sys.argv) >= 2 and sys.argv[1] == "clean":
+ # Delete generated _pb2.py files and .pyc files in the code tree.
+ for (dirpath, dirnames, filenames) in os.walk("."):
+ for filename in filenames:
+ filepath = os.path.join(dirpath, filename)
+ if filepath.endswith("_pb2.py") or filepath.endswith(".pyc"):
+ os.remove(filepath)
+ else:
+ # Generate necessary .proto file if it doesn't exist.
+ # TODO(kenton): Maybe we should hook this into a distutils command?
+ generate_proto("../src/google/protobuf/descriptor.proto")
+
+ setup(name = 'protobuf',
+ version = '2.0.1-SNAPSHOT',
+ packages = [ 'google' ],
+ namespace_packages = [ 'google' ],
+ test_suite = 'setup.MakeTestSuite',
+ # Must list modules explicitly so that we don't install tests.
+ py_modules = [
+ 'google.protobuf.internal.decoder',
+ 'google.protobuf.internal.encoder',
+ 'google.protobuf.internal.input_stream',
+ 'google.protobuf.internal.message_listener',
+ 'google.protobuf.internal.output_stream',
+ 'google.protobuf.internal.wire_format',
+ 'google.protobuf.descriptor',
+ 'google.protobuf.descriptor_pb2',
+ 'google.protobuf.message',
+ 'google.protobuf.reflection',
+ 'google.protobuf.service',
+ 'google.protobuf.service_reflection',
+ 'google.protobuf.text_format'],
+ url = 'http://code.google.com/p/protobuf/',
+ maintainer = maintainer_email,
+ maintainer_email = 'protobuf@googlegroups.com',
+ license = 'Apache License, Version 2.0',
+ description = 'Protocol Buffers',
+ long_description =
+ "Protocol Buffers are Google's data interchange format.",
+ )
diff --git a/python/stubout.py b/python/stubout.py
new file mode 100755
index 00000000..aee4f2da
--- /dev/null
+++ b/python/stubout.py
@@ -0,0 +1,140 @@
+#!/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/
+
+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/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..2997cdd5
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,255 @@
+## Process this file with automake to produce Makefile.in
+
+if GCC
+# These are good warnings to turn on by default
+AM_CXXFLAGS = $(PTHREAD_CFLAGS) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
+else
+AM_CXXFLAGS = $(PTHREAD_CFLAGS)
+endif
+
+AM_LDFLAGS = $(PTHREAD_CFLAGS)
+
+# If I say "dist_include_DATA", automake complains that $(includedir) is not
+# a "legitimate" directory for DATA. Screw you, automake.
+protodir = $(includedir)
+nobase_dist_proto_DATA = google/protobuf/descriptor.proto
+
+# Not sure why these don't get cleaned automatically.
+clean-local:
+ rm -f *.loT
+
+CLEANFILES = $(protoc_outputs) unittest_proto_middleman
+
+MAINTAINERCLEANFILES = \
+ Makefile.in
+
+nobase_include_HEADERS = \
+ google/protobuf/stubs/common.h \
+ google/protobuf/descriptor.h \
+ google/protobuf/descriptor.pb.h \
+ google/protobuf/descriptor_database.h \
+ google/protobuf/dynamic_message.h \
+ google/protobuf/extension_set.h \
+ google/protobuf/generated_message_reflection.h \
+ google/protobuf/message.h \
+ google/protobuf/reflection_ops.h \
+ google/protobuf/repeated_field.h \
+ google/protobuf/service.h \
+ google/protobuf/text_format.h \
+ google/protobuf/unknown_field_set.h \
+ google/protobuf/wire_format.h \
+ google/protobuf/wire_format_inl.h \
+ google/protobuf/io/coded_stream.h \
+ google/protobuf/io/printer.h \
+ google/protobuf/io/tokenizer.h \
+ google/protobuf/io/zero_copy_stream.h \
+ google/protobuf/io/zero_copy_stream_impl.h \
+ google/protobuf/compiler/code_generator.h \
+ google/protobuf/compiler/command_line_interface.h \
+ google/protobuf/compiler/importer.h \
+ google/protobuf/compiler/parser.h \
+ google/protobuf/compiler/cpp/cpp_generator.h \
+ google/protobuf/compiler/java/java_generator.h \
+ google/protobuf/compiler/python/python_generator.h
+
+lib_LTLIBRARIES = libprotobuf.la libprotoc.la
+
+libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
+libprotobuf_la_LDFLAGS = -version-info 0:0:0
+libprotobuf_la_SOURCES = \
+ google/protobuf/stubs/common.cc \
+ google/protobuf/stubs/hash.cc \
+ google/protobuf/stubs/hash.h \
+ google/protobuf/stubs/map-util.cc \
+ google/protobuf/stubs/map-util.h \
+ google/protobuf/stubs/stl_util-inl.cc \
+ google/protobuf/stubs/stl_util-inl.h \
+ google/protobuf/stubs/substitute.cc \
+ google/protobuf/stubs/substitute.h \
+ google/protobuf/stubs/strutil.cc \
+ google/protobuf/stubs/strutil.h \
+ google/protobuf/descriptor.cc \
+ google/protobuf/descriptor.pb.cc \
+ google/protobuf/descriptor_database.cc \
+ google/protobuf/dynamic_message.cc \
+ google/protobuf/extension_set.cc \
+ google/protobuf/generated_message_reflection.cc \
+ google/protobuf/message.cc \
+ google/protobuf/reflection_ops.cc \
+ google/protobuf/repeated_field.cc \
+ google/protobuf/service.cc \
+ google/protobuf/text_format.cc \
+ google/protobuf/unknown_field_set.cc \
+ google/protobuf/wire_format.cc \
+ google/protobuf/io/coded_stream.cc \
+ google/protobuf/io/printer.cc \
+ google/protobuf/io/tokenizer.cc \
+ google/protobuf/io/zero_copy_stream.cc \
+ google/protobuf/io/zero_copy_stream_impl.cc \
+ google/protobuf/compiler/importer.cc \
+ google/protobuf/compiler/parser.cc
+
+libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
+libprotoc_la_LDFLAGS = -version-info 0:0:0
+libprotoc_la_SOURCES = \
+ google/protobuf/compiler/code_generator.cc \
+ google/protobuf/compiler/command_line_interface.cc \
+ google/protobuf/compiler/cpp/cpp_enum.cc \
+ google/protobuf/compiler/cpp/cpp_enum.h \
+ google/protobuf/compiler/cpp/cpp_enum_field.cc \
+ google/protobuf/compiler/cpp/cpp_enum_field.h \
+ google/protobuf/compiler/cpp/cpp_extension.cc \
+ google/protobuf/compiler/cpp/cpp_extension.h \
+ google/protobuf/compiler/cpp/cpp_field.cc \
+ google/protobuf/compiler/cpp/cpp_field.h \
+ google/protobuf/compiler/cpp/cpp_file.cc \
+ google/protobuf/compiler/cpp/cpp_file.h \
+ google/protobuf/compiler/cpp/cpp_generator.cc \
+ google/protobuf/compiler/cpp/cpp_helpers.cc \
+ google/protobuf/compiler/cpp/cpp_helpers.h \
+ google/protobuf/compiler/cpp/cpp_message.cc \
+ google/protobuf/compiler/cpp/cpp_message.h \
+ google/protobuf/compiler/cpp/cpp_message_field.cc \
+ google/protobuf/compiler/cpp/cpp_message_field.h \
+ google/protobuf/compiler/cpp/cpp_primitive_field.cc \
+ google/protobuf/compiler/cpp/cpp_primitive_field.h \
+ google/protobuf/compiler/cpp/cpp_service.cc \
+ google/protobuf/compiler/cpp/cpp_service.h \
+ google/protobuf/compiler/cpp/cpp_string_field.cc \
+ google/protobuf/compiler/cpp/cpp_string_field.h \
+ google/protobuf/compiler/java/java_enum.cc \
+ google/protobuf/compiler/java/java_enum.h \
+ google/protobuf/compiler/java/java_enum_field.cc \
+ google/protobuf/compiler/java/java_enum_field.h \
+ google/protobuf/compiler/java/java_extension.cc \
+ google/protobuf/compiler/java/java_extension.h \
+ google/protobuf/compiler/java/java_field.cc \
+ google/protobuf/compiler/java/java_field.h \
+ google/protobuf/compiler/java/java_file.cc \
+ google/protobuf/compiler/java/java_file.h \
+ google/protobuf/compiler/java/java_generator.cc \
+ google/protobuf/compiler/java/java_helpers.cc \
+ google/protobuf/compiler/java/java_helpers.h \
+ google/protobuf/compiler/java/java_message.cc \
+ google/protobuf/compiler/java/java_message.h \
+ google/protobuf/compiler/java/java_message_field.cc \
+ google/protobuf/compiler/java/java_message_field.h \
+ google/protobuf/compiler/java/java_primitive_field.cc \
+ google/protobuf/compiler/java/java_primitive_field.h \
+ google/protobuf/compiler/java/java_service.cc \
+ google/protobuf/compiler/java/java_service.h \
+ google/protobuf/compiler/python/python_generator.cc
+
+bin_PROGRAMS = protoc
+protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+protoc_SOURCES = google/protobuf/compiler/main.cc
+
+# Tests ==============================================================
+
+protoc_inputs = \
+ google/protobuf/unittest.proto \
+ google/protobuf/unittest_import.proto \
+ google/protobuf/unittest_mset.proto \
+ google/protobuf/unittest_optimize_for.proto \
+ google/protobuf/unittest_embed_optimize_for.proto \
+ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+
+EXTRA_DIST = \
+ $(protoc_inputs) \
+ solaris/libstdc++.la \
+ google/protobuf/testdata/golden_message \
+ google/protobuf/testdata/text_format_unittest_data.txt \
+ google/protobuf/testdata/text_format_unittest_extensions_data.txt \
+ google/protobuf/package_info.h \
+ google/protobuf/io/package_info.h \
+ google/protobuf/compiler/package_info.h \
+ gtest/CHANGES \
+ gtest/CONTRIBUTORS \
+ gtest/COPYING \
+ gtest/README \
+ gtest/gen_gtest_pred_impl.py
+
+protoc_outputs = \
+ google/protobuf/unittest.pb.cc \
+ google/protobuf/unittest.pb.h \
+ google/protobuf/unittest_import.pb.cc \
+ google/protobuf/unittest_import.pb.h \
+ google/protobuf/unittest_mset.pb.cc \
+ google/protobuf/unittest_mset.pb.h \
+ google/protobuf/unittest_optimize_for.pb.cc \
+ google/protobuf/unittest_optimize_for.pb.h \
+ google/protobuf/unittest_embed_optimize_for.pb.cc \
+ google/protobuf/unittest_embed_optimize_for.pb.h \
+ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \
+ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
+
+BUILT_SOURCES = $(protoc_outputs)
+
+# This rule is a little weird. The first prereq is the protoc executable
+# and the rest are its inputs. Therefore, $^ -- which expands to the
+# list of prereqs -- is actually a valid command. We have to place "./" in
+# front of it in case protoc is in the current directory. protoc allows
+# flags to appear after input file names, so we happily stick the flags on
+# the end.
+#
+# For reference, if we didn't have to worry about VPATH (i.e., building from
+# a directory other than the package root), we could have just written this:
+# ./protoc$(EXEEXT) -I$(srcdir) --cpp_out=. $(protoc_inputs)
+unittest_proto_middleman: protoc$(EXEEXT) $(protoc_inputs)
+ ./$^ -I$(srcdir) --cpp_out=.
+ touch unittest_proto_middleman
+
+$(protoc_outputs): unittest_proto_middleman
+
+noinst_PROGRAMS = protobuf-test
+protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+protobuf_test_SOURCES = \
+ google/protobuf/stubs/common_unittest.cc \
+ google/protobuf/stubs/strutil_unittest.cc \
+ google/protobuf/descriptor_database_unittest.cc \
+ google/protobuf/descriptor_unittest.cc \
+ google/protobuf/dynamic_message_unittest.cc \
+ google/protobuf/extension_set_unittest.cc \
+ google/protobuf/generated_message_reflection_unittest.cc \
+ google/protobuf/message_unittest.cc \
+ google/protobuf/reflection_ops_unittest.cc \
+ google/protobuf/repeated_field_unittest.cc \
+ google/protobuf/text_format_unittest.cc \
+ google/protobuf/unknown_field_set_unittest.cc \
+ google/protobuf/wire_format_unittest.cc \
+ google/protobuf/io/coded_stream_unittest.cc \
+ google/protobuf/io/printer_unittest.cc \
+ google/protobuf/io/tokenizer_unittest.cc \
+ google/protobuf/io/zero_copy_stream_unittest.cc \
+ google/protobuf/compiler/command_line_interface_unittest.cc \
+ google/protobuf/compiler/importer_unittest.cc \
+ google/protobuf/compiler/parser_unittest.cc \
+ google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc \
+ google/protobuf/compiler/cpp/cpp_unittest.cc \
+ google/protobuf/test_util.cc \
+ google/protobuf/test_util.h \
+ google/protobuf/testing/googletest.cc \
+ google/protobuf/testing/googletest.h \
+ google/protobuf/testing/file.cc \
+ google/protobuf/testing/file.h \
+ gtest/gtest.cc \
+ gtest/gtest.h \
+ gtest/gtest-death-test.cc \
+ gtest/gtest-death-test.h \
+ gtest/gtest-filepath.cc \
+ gtest/gtest-internal-inl.h \
+ gtest/gtest-message.h \
+ gtest/gtest-port.cc \
+ gtest/gtest-spi.h \
+ gtest/gtest_main.cc \
+ gtest/gtest_pred_impl.h \
+ gtest/gtest_prod.h \
+ gtest/internal/gtest-death-test-internal.h \
+ gtest/internal/gtest-filepath.h \
+ gtest/internal/gtest-internal.h \
+ gtest/internal/gtest-port.h \
+ gtest/internal/gtest-string.h
+
+nodist_protobuf_test_SOURCES = $(protoc_outputs)
+
+TESTS = protobuf-test
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
new file mode 100644
index 00000000..d3a051d0
--- /dev/null
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -0,0 +1,32 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+CodeGenerator::~CodeGenerator() {}
+OutputDirectory::~OutputDirectory() {}
+
+} // 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 00000000..8f9938e3
--- /dev/null
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -0,0 +1,98 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/stubs/common.h>
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+namespace io { class ZeroCopyOutputStream; }
+class FileDescriptor;
+
+namespace compiler {
+
+// Defined in this file.
+class CodeGenerator;
+class OutputDirectory;
+
+// 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 LIBPROTOC_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 by Java and similar languages
+ // to specify which specific class from the proto file is to be generated,
+ // though it could have other uses as well. It is empty if no parameter was
+ // given.
+ //
+ // 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 string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const = 0;
+
+ 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.
+class LIBPROTOC_EXPORT OutputDirectory {
+ public:
+ inline OutputDirectory() {}
+ virtual ~OutputDirectory();
+
+ // 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.pb2.h" and "foo/bar.pb2.cc"; note that
+ // "foo/" is included in these filenames. The filename is not allowed to
+ // contain "." or ".." components.
+ virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory);
+};
+
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..68e88a8e
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -0,0 +1,579 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef _MSC_VER
+#include <io.h>
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <iostream>
+
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#if defined(_WIN32)
+#define mkdir(name, mode) mkdir(name)
+#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
+#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
+
+namespace {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const char* kPathSeparator = ";";
+#else
+static const char* kPathSeparator = ":";
+#endif
+} // namespace
+
+// A MultiFileErrorCollector that prints errors to stderr.
+class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector {
+ public:
+ ErrorPrinter() {}
+ ~ErrorPrinter() {}
+
+ // implements MultiFileErrorCollector ------------------------------
+ void AddError(const string& filename, int line, int column,
+ const string& message) {
+ // Users typically expect 1-based line/column numbers, so we add 1
+ // to each here.
+ cerr << filename;
+ if (line != -1) {
+ cerr << ":" << (line + 1) << ":" << (column + 1);
+ }
+ cerr << ": " << message << endl;
+ }
+};
+
+// -------------------------------------------------------------------
+
+// An OutputDirectory implementation that writes to disk.
+class CommandLineInterface::DiskOutputDirectory : public OutputDirectory {
+ public:
+ DiskOutputDirectory(const string& root);
+ ~DiskOutputDirectory();
+
+ bool VerifyExistence();
+
+ inline bool had_error() { return had_error_; }
+ inline void set_had_error(bool value) { had_error_ = value; }
+
+ // implements OutputDirectory --------------------------------------
+ io::ZeroCopyOutputStream* Open(const string& filename);
+
+ private:
+ string root_;
+ bool had_error_;
+};
+
+// A FileOutputStream that checks for errors in the destructor and reports
+// them. We extend FileOutputStream via wrapping rather than inheritance
+// for two reasons:
+// 1) Implementation inheritance is evil.
+// 2) We need to close the file descriptor *after* the FileOutputStream's
+// destructor is run to make sure it flushes the file contents.
+class CommandLineInterface::ErrorReportingFileOutput
+ : public io::ZeroCopyOutputStream {
+ public:
+ ErrorReportingFileOutput(int file_descriptor,
+ const string& filename,
+ DiskOutputDirectory* directory);
+ ~ErrorReportingFileOutput();
+
+ // implements ZeroCopyOutputStream ---------------------------------
+ bool Next(void** data, int* size) { return file_stream_->Next(data, size); }
+ void BackUp(int count) { file_stream_->BackUp(count); }
+ int64 ByteCount() const { return file_stream_->ByteCount(); }
+
+ private:
+ scoped_ptr<io::FileOutputStream> file_stream_;
+ int file_descriptor_;
+ string filename_;
+ DiskOutputDirectory* directory_;
+};
+
+// -------------------------------------------------------------------
+
+CommandLineInterface::DiskOutputDirectory::DiskOutputDirectory(
+ const string& root)
+ : root_(root), had_error_(false) {
+ // Add a '/' to the end if it doesn't already have one. But don't add a
+ // '/' to an empty string since this probably means the current directory.
+ if (!root_.empty() && root[root_.size() - 1] != '/') {
+ root_ += '/';
+ }
+}
+
+CommandLineInterface::DiskOutputDirectory::~DiskOutputDirectory() {
+}
+
+bool CommandLineInterface::DiskOutputDirectory::VerifyExistence() {
+ if (!root_.empty()) {
+ // Make sure the directory exists. If it isn't a directory, this will fail
+ // because we added a '/' to the end of the name in the constructor.
+ if (access(root_.c_str(), W_OK) == -1) {
+ cerr << root_ << ": " << strerror(errno) << endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+io::ZeroCopyOutputStream* CommandLineInterface::DiskOutputDirectory::Open(
+ const string& filename) {
+ // Recursively create parent directories to the output file.
+ vector<string> parts;
+ SplitStringUsing(filename, "/", &parts);
+ string path_so_far = root_;
+ 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) {
+ cerr << filename << ": while trying to create directory "
+ << path_so_far << ": " << strerror(errno) << endl;
+ had_error_ = true;
+ // Return a dummy stream.
+ return new io::ArrayOutputStream(NULL, 0);
+ }
+ }
+ path_so_far += '/';
+ }
+
+ // Create the output file.
+ int file_descriptor;
+ do {
+ file_descriptor =
+ open((root_ + filename).c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0777);
+ } while (file_descriptor < 0 && errno == EINTR);
+
+ if (file_descriptor < 0) {
+ // Failed to open.
+ cerr << filename << ": " << strerror(errno) << endl;
+ had_error_ = true;
+ // Return a dummy stream.
+ return new io::ArrayOutputStream(NULL, 0);
+ }
+
+ return new ErrorReportingFileOutput(file_descriptor, filename, this);
+}
+
+CommandLineInterface::ErrorReportingFileOutput::ErrorReportingFileOutput(
+ int file_descriptor,
+ const string& filename,
+ DiskOutputDirectory* directory)
+ : file_stream_(new io::FileOutputStream(file_descriptor)),
+ file_descriptor_(file_descriptor),
+ filename_(filename),
+ directory_(directory) {}
+
+CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() {
+ // Check if we had any errors while writing.
+ if (file_stream_->GetErrno() != 0) {
+ cerr << filename_ << ": " << strerror(file_stream_->GetErrno()) << endl;
+ directory_->set_had_error(true);
+ }
+
+ // Close the file stream.
+ if (!file_stream_->Close()) {
+ cerr << filename_ << ": " << strerror(file_stream_->GetErrno()) << endl;
+ directory_->set_had_error(true);
+ }
+}
+
+// ===================================================================
+
+CommandLineInterface::CommandLineInterface()
+ : disallow_services_(false),
+ inputs_are_proto_path_relative_(false) {}
+CommandLineInterface::~CommandLineInterface() {}
+
+void CommandLineInterface::RegisterGenerator(const string& flag_name,
+ CodeGenerator* generator,
+ const string& help_text) {
+ GeneratorInfo info;
+ info.generator = generator;
+ info.help_text = help_text;
+ generators_[flag_name] = info;
+}
+
+int CommandLineInterface::Run(int argc, const char* const argv[]) {
+ Clear();
+ if (!ParseArguments(argc, argv)) return -1;
+
+ // Set up the source tree.
+ DiskSourceTree 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 necessary.
+ if (!inputs_are_proto_path_relative_) {
+ if (!MakeInputsBeProtoPathRelative(&source_tree)) {
+ return -1;
+ }
+ }
+
+ // Allocate the Importer.
+ ErrorPrinter error_collector;
+ DescriptorPool pool;
+ Importer importer(&source_tree, &error_collector);
+
+ // Parse each file and generate output.
+ for (int i = 0; i < input_files_.size(); i++) {
+ // Import the file.
+ const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
+ if (parsed_file == NULL) return -1;
+
+ // Enforce --disallow_services.
+ if (disallow_services_ && parsed_file->service_count() > 0) {
+ cerr << parsed_file->name() << ": This file contains services, but "
+ "--disallow_services was used." << endl;
+ return -1;
+ }
+
+ // Generate output files.
+ for (int i = 0; i < output_directives_.size(); i++) {
+ if (!GenerateOutput(parsed_file, output_directives_[i])) {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void CommandLineInterface::Clear() {
+ proto_path_.clear();
+ input_files_.clear();
+ output_directives_.clear();
+}
+
+bool CommandLineInterface::MakeInputsBeProtoPathRelative(
+ DiskSourceTree* source_tree) {
+ for (int i = 0; i < input_files_.size(); i++) {
+ string virtual_file, shadowing_disk_file;
+ switch (source_tree->DiskFileToVirtualFile(
+ input_files_[i], &virtual_file, &shadowing_disk_file)) {
+ case DiskSourceTree::SUCCESS:
+ input_files_[i] = virtual_file;
+ break;
+ case DiskSourceTree::SHADOWED:
+ cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
+ "by \"" << shadowing_disk_file << "\". Either use the latter "
+ "file as your input or reorder the --proto_path so that the "
+ "former file's location comes first." << endl;
+ return false;
+ case DiskSourceTree::CANNOT_OPEN:
+ cerr << input_files_[i] << ": " << strerror(errno) << endl;
+ return false;
+ case DiskSourceTree::NO_MAPPING:
+ // First check if the file exists at all.
+ if (access(input_files_[i].c_str(), F_OK) < 0) {
+ // File does not even exist.
+ cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
+ } else {
+ cerr << input_files_[i] << ": File does not reside within any path "
+ "specified using --proto_path (or -I). You must specify a "
+ "--proto_path which encompasses this file." << endl;
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
+ executable_name_ = argv[0];
+
+ // Iterate through all arguments and parse them.
+ for (int i = 1; i < argc; i++) {
+ string name, value;
+
+ if (ParseArgument(argv[i], &name, &value)) {
+ // Retured true => Use the next argument as the flag value.
+ if (i + 1 == argc || argv[i+1][0] == '-') {
+ cerr << "Missing value for flag: " << name << endl;
+ return false;
+ } else {
+ ++i;
+ value = argv[i];
+ }
+ }
+
+ if (!InterpretArgument(name, value)) return false;
+ }
+
+ // If no --proto_path was given, use the current working directory.
+ if (proto_path_.empty()) {
+ proto_path_.push_back(make_pair("", "."));
+ }
+
+ // Check some errror cases.
+ if (input_files_.empty()) {
+ cerr << "Missing input file." << endl;
+ return false;
+ }
+ if (output_directives_.empty()) {
+ cerr << "Missing output directives." << endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool CommandLineInterface::ParseArgument(const char* arg,
+ string* name, 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 != NULL) {
+ *name = 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 = 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 == "--version") {
+ // 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;
+}
+
+bool CommandLineInterface::InterpretArgument(const string& name,
+ const string& value) {
+ if (name.empty()) {
+ // Not a flag. Just a filename.
+ if (value.empty()) {
+ cerr << "You seem to have passed an empty string as one of the "
+ "arguments to " << executable_name_ << ". This is actually "
+ "sort of hard to do. Congrats. Unfortunately it is not valid "
+ "input so the program is going to die now." << endl;
+ return false;
+ }
+
+ input_files_.push_back(value);
+
+ } 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.
+ vector<string> parts;
+ SplitStringUsing(value, kPathSeparator, &parts);
+
+ for (int i = 0; i < parts.size(); i++) {
+ string virtual_path;
+ string disk_path;
+
+ int equals_pos = parts[i].find_first_of('=');
+ if (equals_pos == 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()) {
+ cerr << "--proto_path passed empty directory name. (Use \".\" for "
+ "current directory.)" << endl;
+ return false;
+ }
+
+ // Make sure disk path exists, warn otherwise.
+ if (access(disk_path.c_str(), F_OK) < 0) {
+ cerr << disk_path << ": warning: directory does not exist." << endl;
+ }
+
+ proto_path_.push_back(make_pair(virtual_path, disk_path));
+ }
+
+ } else if (name == "-h" || name == "--help") {
+ PrintHelpText();
+ return false; // Exit without running compiler.
+
+ } else if (name == "--version") {
+ if (!version_info_.empty()) {
+ cout << version_info_ << endl;
+ }
+ cout << "libprotoc "
+ << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
+ << endl;
+ return false; // Exit without running compiler.
+
+ } else if (name == "--disallow_services") {
+ disallow_services_ = true;
+
+ } else {
+ // Some other flag. Look it up in the generators list.
+ GeneratorMap::const_iterator iter = generators_.find(name);
+ if (iter == generators_.end()) {
+ cerr << "Unknown flag: " << name << endl;
+ return false;
+ }
+
+ // It's an output flag. Add it to the output directives.
+ OutputDirective directive;
+ directive.name = name;
+ directive.generator = iter->second.generator;
+
+ // Split value at ':' to separate the generator parameter from the
+ // filename.
+ vector<string> parts;
+ SplitStringUsing(value, ":", &parts);
+
+ if (parts.size() == 1) {
+ directive.output_location = parts[0];
+ } else if (parts.size() == 2) {
+ directive.parameter = parts[0];
+ directive.output_location = parts[1];
+ } else {
+ cerr << "Invalid value for flag " << name << "." << endl;
+ return false;
+ }
+
+ output_directives_.push_back(directive);
+ }
+
+ return true;
+}
+
+void CommandLineInterface::PrintHelpText() {
+ // Sorry for indentation here; line wrapping would be uglier.
+ cerr <<
+"Usage: " << executable_name_ << " [OPTION] PROTO_FILE\n"
+"Parse PROTO_FILE and generate output based on the options given:\n"
+" -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
+" imports. May be specified multiple times;\n"
+" directories will be searched in order. If not\n"
+" given, the current working directory is used.\n"
+" --version Show version info and exit.\n"
+" -h, --help Show this text and exit." << endl;
+
+ for (GeneratorMap::iterator iter = generators_.begin();
+ iter != generators_.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.
+ cerr << " " << iter->first << "=OUT_DIR "
+ << string(19 - iter->first.size(), ' ') // Spaces for alignment.
+ << iter->second.help_text << endl;
+ }
+}
+
+bool CommandLineInterface::GenerateOutput(
+ const FileDescriptor* parsed_file,
+ const OutputDirective& output_directive) {
+ // Create the output directory.
+ DiskOutputDirectory output_directory(output_directive.output_location);
+ if (!output_directory.VerifyExistence()) {
+ return false;
+ }
+
+ // Opened successfully. Write it.
+
+ // Call the generator.
+ string error;
+ if (!output_directive.generator->Generate(
+ parsed_file, output_directive.parameter, &output_directory, &error)) {
+ // Generator returned an error.
+ cerr << output_directive.name << ": " << error << endl;
+ return false;
+ }
+
+ // Check for write errors.
+ if (output_directory.had_error()) {
+ return false;
+ }
+
+ return true;
+}
+
+
+} // 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 00000000..d3cae75e
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -0,0 +1,210 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/stubs/common.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <utility>
+
+namespace google {
+namespace protobuf {
+
+class FileDescriptor; // descriptor.h
+
+namespace compiler {
+
+class CodeGenerator; // 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 foo.proto
+//
+// For a full description of the command-line syntax, invoke it with --help.
+class LIBPROTOC_EXPORT CommandLineInterface {
+ public:
+ 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 string& flag_name,
+ CodeGenerator* generator,
+ const string& help_text);
+
+ // 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[]);
+
+ // Call SetInputsAreCwdRelative(true) if the input files given on the command
+ // line should be interpreted relative to the proto import path specified
+ // using --proto_path or -I flags. Otherwise, input file names will be
+ // interpreted relative to the current working directory (or as absolute
+ // paths if they start with '/'), though they must still reside inside
+ // a directory given by --proto_path or the compiler will fail. The latter
+ // mode is generally more intuitive and easier to use, especially e.g. when
+ // defining implicit rules in Makefiles.
+ void SetInputsAreProtoPathRelative(bool enable) {
+ inputs_are_proto_path_relative_ = 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 string& text) {
+ version_info_ = text;
+ }
+
+
+ private:
+ // -----------------------------------------------------------------
+
+ class ErrorPrinter;
+ class DiskOutputDirectory;
+ class ErrorReportingFileOutput;
+
+ // Clear state from previous Run().
+ void Clear();
+
+ // 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. This
+ // is only used if inputs_are_proto_path_relative_ is false.
+ bool MakeInputsBeProtoPathRelative(
+ DiskSourceTree* source_tree);
+
+ // Parse all command-line arguments.
+ bool ParseArguments(int argc, const char* const argv[]);
+
+ // Parses a command-line argument into a name/value pair. Returns
+ // true if the next argument in the argv should be used as the value,
+ // false otherwise.
+ //
+ // Exmaples:
+ // "-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, string* name, string* value);
+
+ // Interprets arguments parsed with ParseArgument.
+ bool InterpretArgument(const string& name, const string& value);
+
+ // Print the --help text to stderr.
+ void PrintHelpText();
+
+ // Generate the given output file from the given input.
+ struct OutputDirective; // see below
+ bool GenerateOutput(const FileDescriptor* proto_file,
+ const OutputDirective& output_directive);
+
+ // -----------------------------------------------------------------
+
+ // The name of the executable as invoked (i.e. argv[0]).
+ string executable_name_;
+
+ // Version info set with SetVersionInfo().
+ string version_info_;
+
+ // Map from flag names to registered generators.
+ struct GeneratorInfo {
+ CodeGenerator* generator;
+ string help_text;
+ };
+ typedef map<string, GeneratorInfo> GeneratorMap;
+ GeneratorMap generators_;
+
+ // Stuff parsed from command line.
+ vector<pair<string, string> > proto_path_; // Search path for proto files.
+ vector<string> input_files_; // Names of the input proto files.
+
+ // output_directives_ lists all the files we are supposed to output and what
+ // generator to use for each.
+ struct OutputDirective {
+ string name;
+ CodeGenerator* generator;
+ string parameter;
+ string output_location;
+ };
+ vector<OutputDirective> output_directives_;
+
+ // Was the --disallow_services flag used?
+ bool disallow_services_;
+
+ // See SetInputsAreProtoPathRelative().
+ bool inputs_are_proto_path_relative_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface);
+};
+
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..1b1458de
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -0,0 +1,964 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+namespace {
+
+class CommandLineInterfaceTest : public testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+ // 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 string& command);
+
+ // -----------------------------------------------------------------
+ // Methods to set up the test (called before Run()).
+
+ class MockCodeGenerator;
+
+ // Registers a MockCodeGenerator with the given name.
+ MockCodeGenerator* RegisterGenerator(const string& generator_name,
+ const string& flag_name,
+ const string& filename,
+ const string& help_text);
+ MockCodeGenerator* RegisterErrorGenerator(const string& generator_name,
+ const string& error_text,
+ const string& flag_name,
+ const string& filename,
+ const string& help_text);
+
+ // Create a temp file within temp_directory_ with the given name.
+ // The containing directory is also created if necessary.
+ void CreateTempFile(const string& name, const string& contents);
+
+ void SetInputsAreProtoPathRelative(bool enable) {
+ cli_.SetInputsAreProtoPathRelative(enable);
+ }
+
+ // -----------------------------------------------------------------
+ // 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 string& expected_text);
+
+ // Checks that Run() returned non-zero and the stderr contains the given
+ // substring.
+ void ExpectErrorSubstring(const string& expected_substring);
+
+ // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
+ // does not fail otherwise.
+ bool HasAlternateErrorSubstring(const string& expected_substring);
+
+ // Checks that MockCodeGenerator::Generate() was called in the given
+ // context. 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 string& generator_name,
+ const string& parameter,
+ const string& proto_name,
+ const string& message_name,
+ const string& output_file);
+
+ private:
+ // The object we are testing.
+ CommandLineInterface cli_;
+
+ // 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.
+ string temp_directory_;
+
+ // The result of Run().
+ int return_code_;
+
+ // The captured stderr output.
+ string error_text_;
+
+ // Pointers which need to be deleted later.
+ vector<MockCodeGenerator*> mock_generators_to_delete_;
+};
+
+// A mock CodeGenerator which outputs information about the context in which
+// it was called, which can then be checked. Output is written to a filename
+// constructed by concatenating the filename_prefix (given to the constructor)
+// with the proto file name, separated by a '.'.
+class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator {
+ public:
+ // Create a MockCodeGenerator whose Generate() method returns true.
+ MockCodeGenerator(const string& name, const string& filename_prefix);
+
+ // Create a MockCodeGenerator whose Generate() method returns false
+ // and sets the error string to the given string.
+ MockCodeGenerator(const string& name, const string& filename_prefix,
+ const string& error);
+
+ ~MockCodeGenerator();
+
+ void set_expect_write_error(bool value) {
+ expect_write_error_ = value;
+ }
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const;
+
+ private:
+ string name_;
+ string filename_prefix_;
+ bool return_error_;
+ string error_;
+ bool expect_write_error_;
+};
+
+// ===================================================================
+
+void CommandLineInterfaceTest::SetUp() {
+ // Most of these tests were written before this option was added, so we
+ // run with the option on (which used to be the only way) except in certain
+ // tests where we turn it off.
+ cli_.SetInputsAreProtoPathRelative(true);
+
+ 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 (File::Exists(temp_directory_)) {
+ File::DeleteRecursively(temp_directory_, NULL, NULL);
+ }
+
+ // Create the temp directory.
+ GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE));
+}
+
+void CommandLineInterfaceTest::TearDown() {
+ // Delete the 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 string& command) {
+ vector<string> args;
+ SplitStringUsing(command, " ", &args);
+
+ scoped_array<const char*> argv(new const char*[args.size()]);
+
+ for (int i = 0; i < args.size(); i++) {
+ args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
+ argv[i] = args[i].c_str();
+ }
+
+ CaptureTestStderr();
+
+ return_code_ = cli_.Run(args.size(), argv.get());
+
+ error_text_ = GetCapturedTestStderr();
+}
+
+// -------------------------------------------------------------------
+
+CommandLineInterfaceTest::MockCodeGenerator*
+CommandLineInterfaceTest::RegisterGenerator(
+ const string& generator_name,
+ const string& flag_name,
+ const string& filename,
+ const string& help_text) {
+ MockCodeGenerator* generator =
+ new MockCodeGenerator(generator_name, filename);
+ mock_generators_to_delete_.push_back(generator);
+
+ cli_.RegisterGenerator(flag_name, generator, help_text);
+ return generator;
+}
+
+CommandLineInterfaceTest::MockCodeGenerator*
+CommandLineInterfaceTest::RegisterErrorGenerator(
+ const string& generator_name,
+ const string& error_text,
+ const string& flag_name,
+ const string& filename_prefix,
+ const string& help_text) {
+ MockCodeGenerator* generator =
+ new MockCodeGenerator(generator_name, filename_prefix, error_text);
+ mock_generators_to_delete_.push_back(generator);
+
+ cli_.RegisterGenerator(flag_name, generator, help_text);
+ return generator;
+}
+
+void CommandLineInterfaceTest::CreateTempFile(
+ const string& name,
+ const string& contents) {
+ // Create parent directory, if necessary.
+ string::size_type slash_pos = name.find_last_of('/');
+ if (slash_pos != string::npos) {
+ string dir = name.substr(0, slash_pos);
+ File::RecursivelyCreateDir(temp_directory_ + "/" + dir, 0777);
+ }
+
+ // Write file.
+ string full_name = temp_directory_ + "/" + name;
+ File::WriteStringToFileOrDie(contents, full_name);
+}
+
+// -------------------------------------------------------------------
+
+void CommandLineInterfaceTest::ExpectNoErrors() {
+ EXPECT_EQ(0, return_code_);
+ EXPECT_EQ("", error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectErrorText(const string& expected_text) {
+ EXPECT_NE(0, return_code_);
+ EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true),
+ error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectErrorSubstring(
+ const string& expected_substring) {
+ EXPECT_NE(0, return_code_);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+}
+
+bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
+ const string& expected_substring) {
+ EXPECT_NE(0, return_code_);
+ return error_text_.find(expected_substring) != string::npos;
+}
+
+void CommandLineInterfaceTest::ExpectGenerated(
+ const string& generator_name,
+ const string& parameter,
+ const string& proto_name,
+ const string& message_name,
+ const string& output_file_prefix) {
+ // Open and read the file.
+ string output_file = output_file_prefix + "." + proto_name;
+ string file_contents;
+ ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file,
+ &file_contents))
+ << "Failed to open file: " + output_file;
+
+ // Check that the contents are as we expect.
+ string expected_contents =
+ generator_name + ": " + parameter + ", " + proto_name + ", " +
+ message_name + "\n";
+ EXPECT_EQ(expected_contents, file_contents)
+ << "Output file did not have expected contents: " + output_file;
+}
+
+// ===================================================================
+
+CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator(
+ const string& name, const string& filename_prefix)
+ : name_(name),
+ filename_prefix_(filename_prefix),
+ return_error_(false),
+ expect_write_error_(false) {
+}
+
+CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator(
+ const string& name, const string& filename_prefix, const string& error)
+ : name_(name),
+ filename_prefix_(filename_prefix),
+ return_error_(true),
+ error_(error),
+ expect_write_error_(false) {
+}
+
+CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {}
+
+bool CommandLineInterfaceTest::MockCodeGenerator::Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filename_prefix_ + "." + file->name()));
+ io::Printer printer(output.get(), '$');
+ map<string, string> vars;
+ vars["name"] = name_;
+ vars["parameter"] = parameter;
+ vars["proto_name"] = file->name();
+ vars["message_name"] = file->message_type_count() > 0 ?
+ file->message_type(0)->full_name().c_str() : "(none)";
+
+ printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n");
+
+ if (expect_write_error_) {
+ EXPECT_TRUE(printer.failed());
+ } else {
+ EXPECT_FALSE(printer.failed());
+ }
+
+ *error = error_;
+ return !return_error_;
+}
+
+// ===================================================================
+
+TEST_F(CommandLineInterfaceTest, BasicOutput) {
+ // Test that the common case works.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputs) {
+ // Test parsing multiple input files.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ CreateTempFile("bar.proto",
+ "syntax = \"proto2\";\n"
+ "message Bar {}\n");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir foo.proto bar.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
+ ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, CreateDirectory) {
+ // Test that when we output to a sub-directory, it is created.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "bar/baz/output.test", "Test output.");
+
+ 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", "bar/baz/output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
+ // Test that generator parameters are correctly parsed from the command line.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("protocol_compiler --test_out=TestParameter:$tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "TestParameter",
+ "foo.proto", "Foo", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, PathLookup) {
+ // Test that specifying multiple directories in the proto search path works.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
+ // Same as PathLookup, but we provide the proto_path in a single flag.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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");
+
+#undef PATH_SEPARATOR
+#if defined(_WIN32)
+#define PATH_SEPARATOR ";"
+#else
+#define PATH_SEPARATOR ":"
+#endif
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir/a"PATH_SEPARATOR"$tmpdir/b foo.proto");
+
+#undef PATH_SEPARATOR
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, NonRootMapping) {
+ // Test setting up a search path mapping a directory to a non-root location.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleGenerators) {
+ // Test that we can have multiple generators and use both in one invocation,
+ // each with a different output directory.
+
+ RegisterGenerator("test_generator_1", "--test1_out",
+ "output1.test", "Test output 1.");
+ RegisterGenerator("test_generator_2", "--test2_out",
+ "output2.test", "Test output 2.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+ // Create the "a" and "b" sub-directories.
+ CreateTempFile("a/dummy", "");
+ CreateTempFile("b/dummy", "");
+
+ Run("protocol_compiler "
+ "--test1_out=$tmpdir/a "
+ "--test2_out=$tmpdir/b "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test");
+ ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test");
+}
+
+TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) {
+ // Test that --disallow_services doesn't cause a problem when there are no
+ // services.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) {
+ // Test that --disallow_services produces an error when there are services.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) {
+ // Test that we can accept working-directory-relative input files.
+
+ SetInputsAreProtoPathRelative(false);
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+// -------------------------------------------------------------------
+
+TEST_F(CommandLineInterfaceTest, ParseErrors) {
+ // Test that parse errors are reported.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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, ParseErrorsMultipleFiles) {
+ // Test that parse errors are reported from multiple files.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ // 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: Import \"bar.proto\" was not found or had errors.\n"
+ "foo.proto: Import \"bar.proto\" was not found or had errors.\n"
+ "foo.proto: Import \"baz.proto\" was not found or had errors.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, InputNotFoundError) {
+ // Test what happens if the input file is not found.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectErrorText(
+ "foo.proto: File not found.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) {
+ // Test what happens when a working-directory-relative input file is not
+ // found.
+
+ SetInputsAreProtoPathRelative(false);
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir $tmpdir/foo.proto");
+
+ ExpectErrorText(
+ "$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.
+
+ SetInputsAreProtoPathRelative(false);
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) {
+ // Check what happens if the input file is not found *and* is not mapped
+ // in the proto_path.
+
+ SetInputsAreProtoPathRelative(false);
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ // 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: 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.
+
+ SetInputsAreProtoPathRelative(false);
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir/foo foo.proto");
+
+ ExpectErrorText(
+ "$tmpdir/foo: warning: directory does not exist.\n"
+ "foo.proto: File not found.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingInputError) {
+ // Test that we get an error if no inputs are given.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir");
+
+ ExpectErrorText("Missing input file.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingOutputError) {
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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) {
+ MockCodeGenerator* generator =
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+ generator->set_expect_write_error(true);
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ // Create a directory blocking our output location.
+ CreateTempFile("output.test.foo.proto/foo", "");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
+ if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) {
+ return;
+ }
+#endif
+
+ ExpectErrorSubstring("output.test.foo.proto: Is a directory");
+}
+
+TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) {
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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, OutputDirectoryIsFileError) {
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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) {
+ RegisterErrorGenerator("error_generator", "Test error message.",
+ "--error_out", "output.test", "Test error output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("protocol_compiler --error_out=$tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectErrorSubstring("--error_out: Test error message.");
+}
+
+TEST_F(CommandLineInterfaceTest, HelpText) {
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+ RegisterErrorGenerator("error_generator", "Test error message.",
+ "--error_out", "output.test", "Test error output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("test_exec_name --help");
+
+ ExpectErrorSubstring("Usage: test_exec_name ");
+ ExpectErrorSubstring("--test_out=OUT_DIR");
+ ExpectErrorSubstring("Test output.");
+ ExpectErrorSubstring("--error_out=OUT_DIR");
+ ExpectErrorSubstring("Test error output.");
+}
+
+// -------------------------------------------------------------------
+// Flag parsing tests
+
+TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) {
+ // Test that a single-character flag works.
+
+ RegisterGenerator("test_generator", "-o",
+ "output.test", "Test output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("protocol_compiler -o$tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) {
+ // Test that separating the flag value with a space works.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) {
+ // Test that separating the flag value with a space works for
+ // single-character flags.
+
+ RegisterGenerator("test_generator", "-o",
+ "output.test", "Test output.");
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("protocol_compiler -o $tmpdir "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingValueError) {
+ // Test that we get an error if a flag is missing its value.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ 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.
+
+ RegisterGenerator("test_generator", "--test_out",
+ "output.test", "Test output.");
+
+ Run("protocol_compiler --test_out");
+
+ ExpectErrorText("Missing value for flag: --test_out\n");
+}
+
+} // anonymous namespace
+
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
new file mode 100644
index 00000000..daa66c8c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -0,0 +1,135 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This test insures that google/protobuf/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/compiler/cpp/cpp_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/stl_util-inl.h>
+#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename, int line, int column,
+ const string& message) {
+ strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
+ filename, line, column, message);
+ }
+};
+
+class MockOutputDirectory : public OutputDirectory {
+ public:
+ MockOutputDirectory() {}
+ ~MockOutputDirectory() {
+ STLDeleteValues(&files_);
+ }
+
+ void ExpectFileMatches(const string& virtual_filename,
+ const string& physical_filename) {
+ string* expected_contents = FindPtrOrNull(files_, virtual_filename);
+ ASSERT_TRUE(expected_contents != NULL)
+ << "Generator failed to generate file: " << virtual_filename;
+
+ string actual_contents;
+ File::ReadFileToStringOrDie(
+ TestSourceDir() + "/" + physical_filename,
+ &actual_contents);
+ EXPECT_TRUE(actual_contents == *expected_contents)
+ << physical_filename << " needs to be regenerated. Please run "
+ "generate_descriptor_proto.sh and add this file "
+ "to your CL.";
+ }
+
+ // implements OutputDirectory --------------------------------------
+
+ virtual io::ZeroCopyOutputStream* Open(const string& filename) {
+ string** map_slot = &files_[filename];
+ if (*map_slot != NULL) delete *map_slot;
+ *map_slot = new string;
+
+ return new io::StringOutputStream(*map_slot);
+ }
+
+ private:
+ map<string, string*> files_;
+};
+
+TEST(BootstrapTest, GeneratedDescriptorMatches) {
+ MockErrorCollector error_collector;
+ DiskSourceTree source_tree;
+ source_tree.MapPath("", TestSourceDir());
+ Importer importer(&source_tree, &error_collector);
+ const FileDescriptor* proto_file =
+ importer.Import("google/protobuf/descriptor.proto");
+ EXPECT_EQ("", error_collector.text_);
+ ASSERT_TRUE(proto_file != NULL);
+
+ CppGenerator generator;
+ MockOutputDirectory output_directory;
+ string error;
+ string parameter;
+ parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
+ ASSERT_TRUE(generator.Generate(proto_file, parameter,
+ &output_directory, &error));
+
+ output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h",
+ "google/protobuf/descriptor.pb.h");
+ output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc",
+ "google/protobuf/descriptor.pb.cc");
+}
+
+} // namespace
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
new file mode 100644
index 00000000..f78d60d8
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -0,0 +1,196 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <set>
+#include <map>
+
+#include <google/protobuf/compiler/cpp/cpp_enum.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
+ const string& dllexport_decl)
+ : descriptor_(descriptor),
+ classname_(ClassName(descriptor, false)),
+ dllexport_decl_(dllexport_decl) {
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::GenerateDefinition(io::Printer* printer) {
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["short_name"] = descriptor_->name();
+
+ printer->Print(vars, "enum $classname$ {\n");
+ printer->Indent();
+
+ const EnumValueDescriptor* min_value = descriptor_->value(0);
+ const EnumValueDescriptor* max_value = descriptor_->value(0);
+
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ vars["name"] = descriptor_->value(i)->name();
+ vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+ vars["prefix"] = (descriptor_->containing_type() == NULL) ?
+ "" : classname_ + "_";
+
+ printer->Print(vars, "$prefix$$name$ = $number$,\n");
+
+ 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);
+ }
+ }
+
+ printer->Outdent();
+ printer->Print("};\n");
+
+ vars["min_name"] = min_value->name();
+ vars["max_name"] = max_value->name();
+
+ if (dllexport_decl_.empty()) {
+ vars["dllexport"] = "";
+ } else {
+ vars["dllexport"] = dllexport_decl_ + " ";
+ }
+
+ printer->Print(vars,
+ "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"
+ "$dllexport$bool $classname$_IsValid(int value);\n"
+ "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
+ "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
+ "\n");
+}
+
+void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
+ map<string, string> vars;
+ vars["nested_name"] = descriptor_->name();
+ vars["classname"] = classname_;
+ printer->Print(vars, "typedef $classname$ $nested_name$;\n");
+
+ for (int j = 0; j < descriptor_->value_count(); j++) {
+ vars["tag"] = descriptor_->value(j)->name();
+ printer->Print(vars,
+ "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
+ }
+
+ printer->Print(vars,
+ "static inline const ::google::protobuf::EnumDescriptor*\n"
+ "$nested_name$_descriptor() {\n"
+ " return $classname$_descriptor();\n"
+ "}\n"
+ "static inline bool $nested_name$_IsValid(int value) {\n"
+ " return $classname$_IsValid(value);\n"
+ "}\n"
+ "static const $nested_name$ $nested_name$_MIN =\n"
+ " $classname$_$nested_name$_MIN;\n"
+ "static const $nested_name$ $nested_name$_MAX =\n"
+ " $classname$_$nested_name$_MAX;\n");
+}
+
+void EnumGenerator::GenerateDescriptorInitializer(
+ io::Printer* printer, int index) {
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["index"] = SimpleItoa(index);
+
+ if (descriptor_->containing_type() == NULL) {
+ printer->Print(vars,
+ "$classname$_descriptor_ = file->enum_type($index$);\n");
+ } else {
+ vars["parent"] = ClassName(descriptor_->containing_type(), false);
+ printer->Print(vars,
+ "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
+ }
+}
+
+void EnumGenerator::GenerateMethods(io::Printer* printer) {
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["builddescriptorsname"] =
+ GlobalBuildDescriptorsName(descriptor_->file()->name());
+
+ printer->Print(vars,
+ "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
+ " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n"
+ " return $classname$_descriptor_;\n"
+ "}\n"
+ "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.
+
+ set<int> numbers;
+ for (int j = 0; j < descriptor_->value_count(); j++) {
+ const EnumValueDescriptor* value = descriptor_->value(j);
+ numbers.insert(value->number());
+ }
+
+ for (set<int>::iterator iter = numbers.begin();
+ iter != numbers.end(); ++iter) {
+ printer->Print(
+ " case $number$:\n",
+ "number", SimpleItoa(*iter));
+ }
+
+ printer->Print(vars,
+ " return true;\n"
+ " default:\n"
+ " return false;\n"
+ " }\n"
+ "}\n"
+ "\n");
+
+ if (descriptor_->containing_type() != NULL) {
+ // We need to "define" the static constants which were declared in the
+ // header, to give the linker a place to put them. Or at least the C++
+ // standard says we have to. MSVC actually insists tha we do _not_ define
+ // them again in the .cc file.
+ printer->Print("#ifndef _MSC_VER\n");
+
+ vars["parent"] = ClassName(descriptor_->containing_type(), false);
+ vars["nested_name"] = descriptor_->name();
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ vars["value"] = descriptor_->value(i)->name();
+ printer->Print(vars,
+ "const $classname$ $parent$::$value$;\n");
+ }
+ printer->Print(vars,
+ "const $classname$ $parent$::$nested_name$_MIN;\n"
+ "const $classname$ $parent$::$nested_name$_MAX;\n");
+
+ printer->Print("#endif // _MSC_VER\n");
+ }
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
new file mode 100644
index 00000000..b30997c9
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumGenerator {
+ public:
+ // See generator.cc for the meaning of dllexport_decl.
+ explicit EnumGenerator(const EnumDescriptor* descriptor,
+ const string& dllexport_decl);
+ ~EnumGenerator();
+
+ // Header stuff.
+
+ // 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);
+
+ // 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);
+
+ // Source file stuff.
+
+ // Generate code that initializes the global variable storing the enum's
+ // descriptor.
+ void GenerateDescriptorInitializer(io::Printer* printer, int index);
+
+ // Generate non-inline methods related to the enum, such as IsValidValue().
+ // Goes in the .cc file.
+ void GenerateMethods(io::Printer* printer);
+
+ private:
+ const EnumDescriptor* descriptor_;
+ string classname_;
+ string dllexport_decl_;
+
+ 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/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
new file mode 100644
index 00000000..e02d7d8a
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -0,0 +1,226 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetEnumVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ const EnumValueDescriptor* default_value = descriptor->default_value_enum();
+
+ (*variables)["name"] = FieldName(descriptor);
+ (*variables)["type"] = ClassName(descriptor->enum_type(), true);
+ (*variables)["default"] = SimpleItoa(default_value->number());
+ (*variables)["index"] = SimpleItoa(descriptor->index());
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+}
+
+} // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::
+EnumFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_, "int $name$_;\n");
+}
+
+void EnumFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline $type$ $name$() const;\n"
+ "inline void set_$name$($type$ value);\n");
+}
+
+void EnumFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline $type$ $classname$::$name$() const {\n"
+ " return static_cast< $type$ >($name$_);\n"
+ "}\n"
+ "inline void $classname$::set_$name$($type$ value) {\n"
+ " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " _set_bit($index$);\n"
+ " $name$_ = value;\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "set_$name$(from.$name$());\n");
+}
+
+void EnumFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ printer->Print(variables_, ",\n$name$_($default$)");
+}
+
+void EnumFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value;\n"
+ "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+ "if ($type$_IsValid(value)) {\n"
+ " set_$name$(static_cast< $type$ >(value));\n"
+ "} else {\n"
+ " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::WriteEnum("
+ "$number$, this->$name$(), output));\n");
+}
+
+void EnumFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ +\n"
+ " ::google::protobuf::internal::WireFormat::EnumSize(this->$name$());\n");
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_, "::google::protobuf::RepeatedField<int> $name$_;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedField<int>& $name$() const;\n"
+ "inline ::google::protobuf::RepeatedField<int>* mutable_$name$();\n"
+ "inline $type$ $name$(int index) const;\n"
+ "inline void set_$name$(int index, $type$ value);\n"
+ "inline void add_$name$($type$ value);\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedField<int>&\n"
+ "$classname$::$name$() const {\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline ::google::protobuf::RepeatedField<int>*\n"
+ "$classname$::mutable_$name$() {\n"
+ " return &$name$_;\n"
+ "}\n"
+ "inline $type$ $classname$::$name$(int index) const {\n"
+ " return static_cast< $type$ >($name$_.Get(index));\n"
+ "}\n"
+ "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+ " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " $name$_.Set(index, value);\n"
+ "}\n"
+ "inline void $classname$::add_$name$($type$ value) {\n"
+ " GOOGLE_DCHECK($type$_IsValid(value));\n"
+ " $name$_.Add(value);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ // Not needed for repeated fields.
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value;\n"
+ "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+ "if ($type$_IsValid(value)) {\n"
+ " add_$name$(static_cast< $type$ >(value));\n"
+ "} else {\n"
+ " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::WriteEnum("
+ "$number$, this->$name$(i), output));\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * $name$_size();\n"
+ "for (int i = 0; i < $name$_size(); i++) {\n"
+ " total_size += ::google::protobuf::internal::WireFormat::EnumSize(\n"
+ " this->$name$(i));\n"
+ "}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
new file mode 100644
index 00000000..a297e961
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+ ~EnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ 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/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
new file mode 100644
index 00000000..87da63d7
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_extension.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
+ const string& dllexport_decl)
+ : descriptor_(descriptor),
+ dllexport_decl_(dllexport_decl) {
+ // 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(" >");
+ 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(descriptor_->cpp_type()));
+ type_traits_.append(" >");
+ break;
+ }
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
+ map<string, string> vars;
+ vars["extendee" ] = ClassName(descriptor_->containing_type(), true);
+ vars["type_traits"] = type_traits_;
+ vars["name" ] = descriptor_->name();
+
+ // If this is a class member, it needs to be declared "static". Otherwise,
+ // it needs to be "extern".
+ vars["qualifier"] =
+ (descriptor_->extension_scope() == NULL) ? "extern" : "static";
+
+ if (!dllexport_decl_.empty()) {
+ vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
+ }
+
+ printer->Print(vars,
+ "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
+ " ::google::protobuf::internal::$type_traits$ > $name$;\n");
+}
+
+void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
+ map<string, string> vars;
+ vars["extendee" ] = ClassName(descriptor_->containing_type(), true);
+ vars["number" ] = SimpleItoa(descriptor_->number());
+ vars["type_traits"] = type_traits_;
+ vars["name" ] = descriptor_->name();
+
+ // If this is a class member, it needs to be declared in its class scope.
+ vars["scope"] = (descriptor_->extension_scope() == NULL) ? "" :
+ ClassName(descriptor_->extension_scope(), false) + "::";
+
+ printer->Print(vars,
+ "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
+ " ::google::protobuf::internal::$type_traits$ > $scope$$name$($number$);\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
new file mode 100644
index 00000000..149dbca9
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -0,0 +1,68 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FieldDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// 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 string& dllexport_decl);
+ ~ExtensionGenerator();
+
+ // Header stuff.
+ void GenerateDeclaration(io::Printer* printer);
+
+ // Source file stuff.
+ void GenerateDefinition(io::Printer* printer);
+
+ private:
+ const FieldDescriptor* descriptor_;
+ string type_traits_;
+ string dllexport_decl_;
+
+ 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/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
new file mode 100644
index 00000000..2b1041be
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -0,0 +1,83 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
+#include <google/protobuf/compiler/cpp/cpp_string_field.h>
+#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
+#include <google/protobuf/compiler/cpp/cpp_message_field.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+FieldGenerator::~FieldGenerator() {}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+ : descriptor_(descriptor),
+ field_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+ // Construct all the FieldGenerators.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
+ }
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
+ if (field->is_repeated()) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return new RepeatedMessageFieldGenerator(field);
+ case FieldDescriptor::CPPTYPE_STRING:
+ return new RepeatedStringFieldGenerator(field);
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return new RepeatedEnumFieldGenerator(field);
+ default:
+ return new RepeatedPrimitiveFieldGenerator(field);
+ }
+ } else {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return new MessageFieldGenerator(field);
+ case FieldDescriptor::CPPTYPE_STRING:
+ return new StringFieldGenerator(field);
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return new EnumFieldGenerator(field);
+ default:
+ return new PrimitiveFieldGenerator(field);
+ }
+ }
+}
+
+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/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
new file mode 100644
index 00000000..d37eb962
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -0,0 +1,127 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class FieldGenerator {
+ public:
+ FieldGenerator() {}
+ virtual ~FieldGenerator();
+
+ // 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 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 lines of code (statements, not declarations) which clear the
+ // field. This is used to define the clear_$name$() method as well as
+ // the Clear() method for the whole message.
+ virtual void GenerateClearingCode(io::Printer* printer) const = 0;
+
+ // 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;
+
+ // Generate any initializers needed for the private members declared by
+ // GeneratePrivateMembers(). These go into the message class's
+ // constructor's initializer list. For each initializer, this method
+ // must print the comma and newline separating it from the *previous*
+ // initializer, not the *next* initailizer. That is, print a ",\n" first,
+ // e.g.:
+ // printer->Print(",\n$name$_($default$)");
+ virtual void GenerateInitializer(io::Printer* printer) const = 0;
+
+ // Generate any code that needs to go in the class's destructor.
+ // Most field types don't need this, so the default implementation is empty.
+ virtual void GenerateDestructorCode(io::Printer* printer) const {}
+
+ // Generate lines to decode this field, which will be placed inside the
+ // message's MergeFromCodedStream() method.
+ virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
+
+ // Generate lines to serialize this field, which are placed within the
+ // message's SerializeWithCachedSizes() method.
+ virtual void GenerateSerializeWithCachedSizes(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;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+ explicit FieldGeneratorMap(const Descriptor* descriptor);
+ ~FieldGeneratorMap();
+
+ const FieldGenerator& get(const FieldDescriptor* field) const;
+
+ private:
+ const Descriptor* descriptor_;
+ scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
+
+ 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/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
new file mode 100644
index 00000000..aea3a4b2
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -0,0 +1,404 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <google/protobuf/compiler/cpp/cpp_enum.h>
+#include <google/protobuf/compiler/cpp/cpp_service.h>
+#include <google/protobuf/compiler/cpp/cpp_extension.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_message.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// ===================================================================
+
+FileGenerator::FileGenerator(const FileDescriptor* file,
+ const string& dllexport_decl)
+ : file_(file),
+ message_generators_(
+ new scoped_ptr<MessageGenerator>[file->message_type_count()]),
+ enum_generators_(
+ new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
+ service_generators_(
+ new scoped_ptr<ServiceGenerator>[file->service_count()]),
+ extension_generators_(
+ new scoped_ptr<ExtensionGenerator>[file->extension_count()]) {
+
+ for (int i = 0; i < file->message_type_count(); i++) {
+ message_generators_[i].reset(
+ new MessageGenerator(file->message_type(i), dllexport_decl));
+ }
+
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ enum_generators_[i].reset(
+ new EnumGenerator(file->enum_type(i), dllexport_decl));
+ }
+
+ for (int i = 0; i < file->service_count(); i++) {
+ service_generators_[i].reset(
+ new ServiceGenerator(file->service(i), dllexport_decl));
+ }
+
+ for (int i = 0; i < file->extension_count(); i++) {
+ extension_generators_[i].reset(
+ new ExtensionGenerator(file->extension(i), dllexport_decl));
+ }
+
+ SplitStringUsing(file_->package(), ".", &package_parts_);
+}
+
+FileGenerator::~FileGenerator() {}
+
+void FileGenerator::GenerateHeader(io::Printer* printer) {
+ string filename_identifier = FilenameIdentifier(file_->name());
+
+ // Generate top of header.
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "\n"
+ "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
+ "\n"
+ "#include <string>\n"
+ "\n",
+ "filename_identifier", filename_identifier);
+
+ printer->Print(
+ "#include <google/protobuf/stubs/common.h>\n"
+ "\n");
+
+ // Verify the protobuf library header version is compatible with the protoc
+ // version before going any further.
+ printer->Print(
+ "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
+ "#error This file was generated by a newer version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please update\n"
+ "#error your headers.\n"
+ "#endif\n"
+ "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
+ "#error This file was generated by an older version of protoc which is\n"
+ "#error incompatible with your Protocol Buffer headers. Please\n"
+ "#error regenerate this file with a newer version of protoc.\n"
+ "#endif\n"
+ "\n",
+ "min_header_version",
+ SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
+ "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
+
+ // OK, it's now safe to #include other files.
+ printer->Print(
+ "#include <google/protobuf/generated_message_reflection.h>\n"
+ "#include <google/protobuf/repeated_field.h>\n"
+ "#include <google/protobuf/extension_set.h>\n");
+
+ if (file_->service_count() > 0) {
+ printer->Print(
+ "#include <google/protobuf/service.h>\n");
+ }
+
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ printer->Print(
+ "#include \"$dependency$.pb.h\"\n",
+ "dependency", StripProto(file_->dependency(i)->name()));
+ }
+
+ // Open namespace.
+ GenerateNamespaceOpeners(printer);
+
+ printer->Print("\n");
+
+ // Generate forward declarations of classes.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateForwardDeclaration(printer);
+ }
+
+ printer->Print("\n");
+
+ // Generate enum definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateEnumDefinitions(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDefinition(printer);
+ }
+
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+
+ // Generate class definitions.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateClassDefinition(printer);
+ }
+
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+
+ // Generate service definitions.
+ for (int i = 0; i < file_->service_count(); i++) {
+ if (i > 0) {
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ service_generators_[i]->GenerateDeclarations(printer);
+ }
+
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+
+ // Declare extension identifiers.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateDeclaration(printer);
+ }
+
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+
+ // Generate class inline methods.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i > 0) {
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+ message_generators_[i]->GenerateInlineMethods(printer);
+ }
+
+ // Close up namespace.
+ GenerateNamespaceClosers(printer);
+
+ printer->Print(
+ "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
+ "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateSource(io::Printer* printer) {
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "\n"
+ "#include \"$basename$.pb.h\"\n"
+ "#include <google/protobuf/descriptor.h>\n"
+ "#include <google/protobuf/io/coded_stream.h>\n"
+ "#include <google/protobuf/reflection_ops.h>\n"
+ "#include <google/protobuf/wire_format_inl.h>\n",
+ "basename", StripProto(file_->name()));
+
+ // For each dependency, write a prototype for that dependency's
+ // BuildDescriptors() function. We don't expose these in the header because
+ // they are internal implementation details, and since this is generated code
+ // we don't have the usual risks involved with declaring external functions
+ // within a .cc file.
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ const FileDescriptor* dependency = file_->dependency(i);
+ // Open the dependency's namespace.
+ vector<string> dependency_package_parts;
+ SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
+ for (int i = 0; i < dependency_package_parts.size(); i++) {
+ printer->Print("namespace $name$ { ",
+ "name", dependency_package_parts[i]);
+ }
+ // Declare its BuildDescriptors() function.
+ printer->Print(
+ "void $function$();",
+ "function", GlobalBuildDescriptorsName(dependency->name()));
+ // Close the namespace.
+ for (int i = 0; i < dependency_package_parts.size(); i++) {
+ printer->Print(" }");
+ }
+ printer->Print("\n");
+ }
+
+ GenerateNamespaceOpeners(printer);
+
+ printer->Print(
+ "\n"
+ "namespace {\n"
+ "\n");
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateDescriptorDeclarations(printer);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ printer->Print(
+ "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
+ "name", ClassName(file_->enum_type(i), false));
+ }
+ for (int i = 0; i < file_->service_count(); i++) {
+ printer->Print(
+ "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
+ "name", file_->service(i)->name());
+ }
+
+ printer->Print(
+ "\n"
+ "} // namespace\n"
+ "\n");
+
+ // Define our externally-visible BuildDescriptors() function.
+ GenerateBuildDescriptors(printer);
+
+ // Generate enums.
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateMethods(printer);
+ }
+
+ // Generate classes.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ message_generators_[i]->GenerateClassMethods(printer);
+ }
+
+ // Generate services.
+ for (int i = 0; i < file_->service_count(); i++) {
+ if (i == 0) printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ service_generators_[i]->GenerateImplementation(printer);
+ }
+
+ // Define extensions.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateDefinition(printer);
+ }
+
+ GenerateNamespaceClosers(printer);
+}
+
+void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
+ // BuildDescriptors() is a file-level procedure which initializes all of
+ // the Descriptor objects for this file. It runs the first time one of the
+ // descriptors is accessed. This will always be at static initialization
+ // time, because every message has a statically-initialized default instance,
+ // and the constructor for a message class accesses its descriptor. See the
+ // constructor and the descriptor() method of message classes.
+ printer->Print(
+ "\n"
+ "void $builddescriptorsname$() {\n"
+ " static bool already_here = false;\n"
+ " if (already_here) return;\n"
+ " already_here = true;\n"
+ " GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+ " ::google::protobuf::DescriptorPool* pool =\n"
+ " ::google::protobuf::DescriptorPool::internal_generated_pool();\n"
+ "\n",
+ "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()));
+ printer->Indent();
+
+ // Call the BuildDescriptors() methods for all of our dependencies, to make
+ // sure they get initialized first.
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ const FileDescriptor* dependency = file_->dependency(i);
+ // Print the namespace prefix for the dependency.
+ vector<string> dependency_package_parts;
+ SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
+ printer->Print("::");
+ for (int i = 0; i < dependency_package_parts.size(); i++) {
+ printer->Print("$name$::",
+ "name", dependency_package_parts[i]);
+ }
+ // Call its BuildDescriptors function.
+ printer->Print(
+ "$name$();\n",
+ "name", GlobalBuildDescriptorsName(dependency->name()));
+ }
+
+ // 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.
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+ string file_data;
+ file_proto.SerializeToString(&file_data);
+
+ printer->Print(
+ "const ::google::protobuf::FileDescriptor* file = pool->InternalBuildGeneratedFile(");
+
+ // Only write 40 bytes per line.
+ static const int kBytesPerLine = 40;
+ for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+ printer->Print("\n \"$data$\"",
+ "data", CEscape(file_data.substr(i, kBytesPerLine)));
+ }
+ printer->Print(
+ ", $size$);\n",
+ "size", SimpleItoa(file_data.size()));
+
+ // Assign all global descriptors.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateDescriptorInitializer(printer, i);
+ }
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
+ }
+ for (int i = 0; i < file_->service_count(); i++) {
+ service_generators_[i]->GenerateDescriptorInitializer(printer, i);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n"
+ "// Force BuildDescriptors() to be called at static initialization time.\n"
+ "struct StaticDescriptorInitializer_$filename$ {\n"
+ " StaticDescriptorInitializer_$filename$() {\n"
+ " $builddescriptorsname$();\n"
+ " }\n"
+ "} static_descriptor_initializer_$filename$_;\n"
+ "\n",
+ "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()),
+ "filename", FilenameIdentifier(file_->name()));
+}
+
+void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
+ if (package_parts_.size() > 0) printer->Print("\n");
+
+ for (int i = 0; i < package_parts_.size(); i++) {
+ printer->Print("namespace $part$ {\n",
+ "part", package_parts_[i]);
+ }
+}
+
+void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
+ if (package_parts_.size() > 0) printer->Print("\n");
+
+ for (int i = package_parts_.size() - 1; i >= 0; i--) {
+ printer->Print("} // namespace $part$\n",
+ "part", package_parts_[i]);
+ }
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
new file mode 100644
index 00000000..f2255ee1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+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.
+ explicit FileGenerator(const FileDescriptor* file,
+ const string& dllexport_decl);
+ ~FileGenerator();
+
+ void GenerateHeader(io::Printer* printer);
+ void GenerateSource(io::Printer* printer);
+
+ private:
+ // Generate the BuildDescriptors() procedure, which builds all descriptors
+ // for types defined in the file.
+ void GenerateBuildDescriptors(io::Printer* printer);
+
+ void GenerateNamespaceOpeners(io::Printer* printer);
+ void GenerateNamespaceClosers(io::Printer* printer);
+
+ const FileDescriptor* file_;
+
+ scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
+ scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
+ scoped_array<scoped_ptr<ServiceGenerator> > service_generators_;
+ scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+
+ // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
+ vector<string> package_parts_;
+
+ 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/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
new file mode 100644
index 00000000..200f6358
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -0,0 +1,135 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_generator.h>
+
+#include <vector>
+#include <utility>
+
+#include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+// Parses a set of comma-delimited name/value pairs, e.g.:
+// "foo=bar,baz,qux=corge"
+// parses to the pairs:
+// ("foo", "bar"), ("baz", ""), ("qux", "corge")
+void ParseOptions(const string& text, vector<pair<string, string> >* output) {
+ vector<string> parts;
+ SplitStringUsing(text, ",", &parts);
+
+ for (int i = 0; i < parts.size(); i++) {
+ string::size_type equals_pos = parts[i].find_first_of('=');
+ pair<string, string> value;
+ if (equals_pos == 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);
+ }
+}
+
+} // namespace
+
+CppGenerator::CppGenerator() {}
+CppGenerator::~CppGenerator() {}
+
+bool CppGenerator::Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const {
+ vector<pair<string, string> > options;
+ ParseOptions(parameter, &options);
+
+ // -----------------------------------------------------------------
+ // parse generator options
+
+ // TODO(kenton): If we ever have more options, we may want to create a
+ // class that encapsulates them which we can pass down to all the
+ // generator classes. Currently we pass dllexport_decl down to all of
+ // them via the constructors, but we don't want to have to add another
+ // constructor parameter for every option.
+
+ // 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.
+ string dllexport_decl;
+
+ for (int i = 0; i < options.size(); i++) {
+ if (options[i].first == "dllexport_decl") {
+ dllexport_decl = options[i].second;
+ } else {
+ *error = "Unknown generator option: " + options[i].first;
+ return false;
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+
+ string basename = StripProto(file->name());
+ basename.append(".pb");
+
+ FileGenerator file_generator(file, dllexport_decl);
+
+ // Generate header.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(basename + ".h"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateHeader(&printer);
+ }
+
+ // Generate cc file.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(basename + ".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/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
new file mode 100644
index 00000000..26fb8e97
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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>
+
+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 LIBPROTOC_EXPORT CppGenerator : public CodeGenerator {
+ public:
+ CppGenerator();
+ ~CppGenerator();
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
new file mode 100644
index 00000000..21de816c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -0,0 +1,197 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+string DotsToUnderscores(const string& name) {
+ return StringReplace(name, ".", "_", true);
+}
+
+string DotsToColons(const string& name) {
+ return StringReplace(name, ".", "::", true);
+}
+
+const char* const kKeywordList[] = {
+ "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
+ "catch", "char", "class", "compl", "const", "const_cast", "continue",
+ "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
+ "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
+ "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
+ "operator", "or", "or_eq", "private", "protected", "public", "register",
+ "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
+ "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
+ "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
+ "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
+};
+
+hash_set<string> MakeKeywordsMap() {
+ hash_set<string> result;
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
+ result.insert(kKeywordList[i]);
+ }
+ return result;
+}
+
+hash_set<string> kKeywords = MakeKeywordsMap();
+
+} // namespace
+
+const char kThickSeparator[] =
+ "// ===================================================================\n";
+const char kThinSeparator[] =
+ "// -------------------------------------------------------------------\n";
+
+string ClassName(const Descriptor* descriptor, bool qualified) {
+ // Find "outer", the descriptor of the top-level message in which
+ // "descriptor" is embedded.
+ const Descriptor* outer = descriptor;
+ while (outer->containing_type() != NULL) outer = outer->containing_type();
+
+ const string& outer_name = outer->full_name();
+ string inner_name = descriptor->full_name().substr(outer_name.size());
+
+ if (qualified) {
+ return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
+ } else {
+ return outer->name() + DotsToUnderscores(inner_name);
+ }
+}
+
+string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
+ if (enum_descriptor->containing_type() == NULL) {
+ if (qualified) {
+ return DotsToColons(enum_descriptor->full_name());
+ } else {
+ return enum_descriptor->name();
+ }
+ } else {
+ string result = ClassName(enum_descriptor->containing_type(), qualified);
+ result += '_';
+ result += enum_descriptor->name();
+ return result;
+ }
+}
+
+string FieldName(const FieldDescriptor* field) {
+ string result = field->name();
+ LowerString(&result);
+ if (kKeywords.count(result) > 0) {
+ result.append("_");
+ }
+ return result;
+}
+
+string StripProto(const string& filename) {
+ if (HasSuffixString(filename, ".protodevel")) {
+ return StripSuffixString(filename, ".protodevel");
+ } else {
+ return StripSuffixString(filename, ".proto");
+ }
+}
+
+const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
+ switch (type) {
+ case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
+ case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
+ case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
+ case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::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 NULL;
+
+ // No default because we want the compiler to complain if any new
+ // CppTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+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 "";
+}
+
+// Convert a file name into a valid identifier.
+string FilenameIdentifier(const string& filename) {
+ 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.
+ result.push_back('_');
+ char buffer[kFastToBufferSize];
+ result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
+ }
+ }
+ return result;
+}
+
+// Return the name of the BuildDescriptors() function for a given file.
+string GlobalBuildDescriptorsName(const string& filename) {
+ return "proto_BuildDescriptors_" + FilenameIdentifier(filename);
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
new file mode 100644
index 00000000..7f57d694
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Commonly-used separator comments. Thick is a line of '=', thin is a line
+// of '-'.
+extern const char kThickSeparator[];
+extern const char kThinSeparator[];
+
+// 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 Qux {} }
+// Then the qualified ClassName for Qux would be:
+// ::foo::bar::Baz_Qux
+// While the non-qualified version would be:
+// Baz_Qux
+string ClassName(const Descriptor* descriptor, bool qualified);
+string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
+
+// Get the (unqualified) name that should be used for this field in C++ code.
+// The name is coerced to lower-case to emulate proto1 behavior. People
+// should be using lowercase-with-underscores style for proto field names
+// anyway, so normally this just returns field->name().
+string FieldName(const FieldDescriptor* field);
+
+// 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();
+}
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
+// Note: non-built-in type names will be qualified, meaning they will start
+// with a ::. If you are using the type as a template parameter, you will
+// need to insure there is a space between the < and the ::, because the
+// ridiculous C++ standard defines "<:" to be a synonym for "[".
+const char* PrimitiveTypeName(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);
+
+// Convert a file name into a valid identifier.
+string FilenameIdentifier(const string& filename);
+
+// Return the name of the BuildDescriptors() function for a given file.
+string GlobalBuildDescriptorsName(const string& filename);
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
new file mode 100644
index 00000000..002b0ad2
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -0,0 +1,1445 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/cpp/cpp_message.h>
+#include <google/protobuf/compiler/cpp/cpp_enum.h>
+#include <google/protobuf/compiler/cpp/cpp_extension.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+namespace {
+
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+ // Print the field's proto-syntax definition as a comment. We don't want to
+ // print group bodies so we cut off after the first line.
+ string def = field->DebugString();
+ printer->Print("// $def$\n",
+ "def", def.substr(0, def.find_first_of('\n')));
+}
+
+struct FieldOrderingByNumber {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) const {
+ return a->number() < b->number();
+ }
+};
+
+const char* kWireTypeNames[] = {
+ "VARINT",
+ "FIXED64",
+ "LENGTH_DELIMITED",
+ "START_GROUP",
+ "END_GROUP",
+ "FIXED32",
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor*[descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
+ return fields;
+}
+
+// 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;
+ }
+};
+
+// 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).
+static bool HasRequiredFields(
+ const Descriptor* type,
+ hash_set<const Descriptor*>* already_seen) {
+ if (already_seen->count(type) > 0) {
+ // Since the first occurrence of a required field causes the whole
+ // function to return true, we can assume that if the type is already
+ // in the cache it didn't have any required fields.
+ 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 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (HasRequiredFields(field->message_type(), already_seen)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool HasRequiredFields(const Descriptor* type) {
+ hash_set<const Descriptor*> already_seen;
+ return HasRequiredFields(type, &already_seen);
+}
+
+}
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor,
+ const string& dllexport_decl)
+ : descriptor_(descriptor),
+ classname_(ClassName(descriptor, false)),
+ dllexport_decl_(dllexport_decl),
+ field_generators_(descriptor),
+ nested_generators_(new scoped_ptr<MessageGenerator>[
+ descriptor->nested_type_count()]),
+ enum_generators_(new scoped_ptr<EnumGenerator>[
+ descriptor->enum_type_count()]),
+ extension_generators_(new scoped_ptr<ExtensionGenerator>[
+ descriptor->extension_count()]) {
+
+ for (int i = 0; i < descriptor->nested_type_count(); i++) {
+ nested_generators_[i].reset(
+ new MessageGenerator(descriptor->nested_type(i), dllexport_decl));
+ }
+
+ for (int i = 0; i < descriptor->enum_type_count(); i++) {
+ enum_generators_[i].reset(
+ new EnumGenerator(descriptor->enum_type(i), dllexport_decl));
+ }
+
+ for (int i = 0; i < descriptor->extension_count(); i++) {
+ extension_generators_[i].reset(
+ new ExtensionGenerator(descriptor->extension(i), dllexport_decl));
+ }
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+void MessageGenerator::
+GenerateForwardDeclaration(io::Printer* printer) {
+ printer->Print("class $classname$;\n",
+ "classname", classname_);
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateForwardDeclaration(printer);
+ }
+}
+
+void MessageGenerator::
+GenerateEnumDefinitions(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateEnumDefinitions(printer);
+ }
+
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDefinition(printer);
+ }
+}
+
+void MessageGenerator::
+GenerateFieldAccessorDeclarations(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ map<string, string> vars;
+ vars["name"] = FieldName(field);
+
+ if (field->is_repeated()) {
+ printer->Print(vars, "inline int $name$_size() const;\n");
+ } else {
+ printer->Print(vars, "inline bool has_$name$() const;\n");
+ }
+
+ printer->Print(vars, "inline void clear_$name$();\n");
+
+ // Generate type-specific accessor declarations.
+ field_generators_.get(field).GenerateAccessorDeclarations(printer);
+
+ printer->Print("\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ // Generate accessors for extensions.
+
+ // Normally I'd generate prototypes here and generate the actual
+ // definitions of these methods in GenerateFieldAccessorDefinitions, but
+ // the prototypes for these silly methods are so absurdly complicated that
+ // it meant way too much repitition.
+ //
+ // 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.
+ printer->Print(
+ // Has, Size, Clear
+ "template <typename _proto_TypeTraits>\n"
+ "inline bool HasExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) const {\n"
+ " return _extensions_.Has(id.number());\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline void ClearExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) {\n"
+ " _extensions_.ClearExtension(id.number());\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline int ExtensionSize(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) const {\n"
+ " return _extensions_.ExtensionSize(id.number());\n"
+ "}\n"
+ "\n"
+
+ // Singular accessors
+ "template <typename _proto_TypeTraits>\n"
+ "inline typename _proto_TypeTraits::ConstType GetExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) const {\n"
+ " return _proto_TypeTraits::Get(id.number(), _extensions_);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline typename _proto_TypeTraits::MutableType MutableExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) {\n"
+ " return _proto_TypeTraits::Mutable(id.number(), &_extensions_);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline void SetExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id,\n"
+ " typename _proto_TypeTraits::ConstType value) {\n"
+ " _proto_TypeTraits::Set(id.number(), value, &_extensions_);\n"
+ "}\n"
+ "\n"
+
+ // Repeated accessors
+ "template <typename _proto_TypeTraits>\n"
+ "inline typename _proto_TypeTraits::ConstType GetExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id,\n"
+ " int index) const {\n"
+ " return _proto_TypeTraits::Get(id.number(), _extensions_, index);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline typename _proto_TypeTraits::MutableType MutableExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id,\n"
+ " int index) {\n"
+ " return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline void SetExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id,\n"
+ " int index, typename _proto_TypeTraits::ConstType value) {\n"
+ " _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline typename _proto_TypeTraits::MutableType AddExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id) {\n"
+ " return _proto_TypeTraits::Add(id.number(), &_extensions_);\n"
+ "}\n"
+ "\n"
+ "template <typename _proto_TypeTraits>\n"
+ "inline void AddExtension(\n"
+ " const ::google::protobuf::internal::ExtensionIdentifier<\n"
+ " $classname$, _proto_TypeTraits>& id,\n"
+ " typename _proto_TypeTraits::ConstType value) {\n"
+ " _proto_TypeTraits::Add(id.number(), value, &_extensions_);\n"
+ "}\n",
+ "classname", classname_);
+ }
+}
+
+void MessageGenerator::
+GenerateFieldAccessorDefinitions(io::Printer* printer) {
+ printer->Print("// $classname$\n\n", "classname", classname_);
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ PrintFieldComment(printer, field);
+
+ map<string, string> vars;
+ vars["name"] = FieldName(field);
+ vars["index"] = SimpleItoa(field->index());
+ vars["classname"] = classname_;
+
+ // Generate has_$name$() or $name$_size().
+ if (field->is_repeated()) {
+ printer->Print(vars,
+ "inline int $classname$::$name$_size() const {\n"
+ " return $name$_.size();\n"
+ "}\n");
+ } else {
+ // Singular field.
+ printer->Print(vars,
+ "inline bool $classname$::has_$name$() const {\n"
+ " return _has_bit($index$);\n"
+ "}\n");
+ }
+
+ // Generate clear_$name$()
+ printer->Print(vars,
+ "inline void $classname$::clear_$name$() {\n");
+
+ printer->Indent();
+ field_generators_.get(field).GenerateClearingCode(printer);
+ printer->Outdent();
+
+ if (!field->is_repeated()) {
+ printer->Print(vars, " _clear_bit($index$);\n");
+ }
+
+ printer->Print("}\n");
+
+ // Generate type-specific accessors.
+ field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+
+ printer->Print("\n");
+ }
+}
+
+void MessageGenerator::
+GenerateClassDefinition(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateClassDefinition(printer);
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["field_count"] = SimpleItoa(descriptor_->field_count());
+ if (dllexport_decl_.empty()) {
+ vars["dllexport"] = "";
+ } else {
+ vars["dllexport"] = dllexport_decl_ + " ";
+ }
+
+ printer->Print(vars,
+ "class $dllexport$$classname$ : public ::google::protobuf::Message {\n"
+ " public:\n");
+ printer->Indent();
+
+ printer->Print(vars,
+ "$classname$();\n"
+ "virtual ~$classname$();\n"
+ "\n"
+ "$classname$(const $classname$& from);\n"
+ "\n"
+ "inline $classname$& operator=(const $classname$& from) {\n"
+ " CopyFrom(from);\n"
+ " return *this;\n"
+ "}\n"
+ "\n"
+ "inline static const $classname$& default_instance() {\n"
+ " return default_instance_;\n"
+ "}\n"
+ "\n"
+ "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
+ " return _reflection_.unknown_fields();\n"
+ "}\n"
+ "\n"
+ "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
+ " return _reflection_.mutable_unknown_fields();\n"
+ "}\n"
+ "\n"
+ "static const ::google::protobuf::Descriptor* descriptor();\n"
+ "\n"
+ "// implements Message ----------------------------------------------\n"
+ "\n"
+ "$classname$* New() const;\n");
+
+ if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(vars,
+ "void CopyFrom(const ::google::protobuf::Message& from);\n"
+ "void MergeFrom(const ::google::protobuf::Message& from);\n"
+ "void CopyFrom(const $classname$& from);\n"
+ "void MergeFrom(const $classname$& from);\n"
+ "void Clear();\n"
+ "bool IsInitialized() const;\n"
+ "int ByteSize() const;\n"
+ "\n"
+ "bool MergePartialFromCodedStream(\n"
+ " ::google::protobuf::io::CodedInputStream* input);\n"
+ "bool SerializeWithCachedSizes(\n"
+ " ::google::protobuf::io::CodedOutputStream* output) const;\n");
+ }
+
+ printer->Print(vars,
+ "int GetCachedSize() const { return _cached_size_; }\n"
+ "private:\n"
+ "void SetCachedSize(int size) const { _cached_size_ = size; }\n"
+ "public:\n"
+ "\n"
+ "const ::google::protobuf::Descriptor* GetDescriptor() const;\n"
+ "const ::google::protobuf::Message::Reflection* GetReflection() const;\n"
+ "::google::protobuf::Message::Reflection* GetReflection();\n"
+ "\n"
+ "// 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);
+ printer->Print("typedef $nested_full_name$ $nested_name$;\n",
+ "nested_name", nested_type->name(),
+ "nested_full_name", ClassName(nested_type, false));
+ }
+
+ if (descriptor_->nested_type_count() > 0) {
+ printer->Print("\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);
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ "// 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);
+ }
+
+ // Generate private members for fields.
+ printer->Outdent();
+ printer->Print(" private:\n");
+ printer->Indent();
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "::google::protobuf::internal::ExtensionSet _extensions_;\n");
+ }
+
+ // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
+ printer->Print(
+ "::google::protobuf::internal::GeneratedMessageReflection _reflection_;\n"
+ "mutable int _cached_size_;\n"
+ "\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GeneratePrivateMembers(printer);
+ }
+
+ // Generate offsets and _has_bits_ boilerplate.
+ printer->Print(vars,
+ "\n"
+ "static const $classname$ default_instance_;\n");
+
+ if (descriptor_->field_count() > 0) {
+ printer->Print(vars,
+ "static const int _offsets_[$field_count$];\n"
+ "\n"
+ "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n");
+ } else {
+ // Zero-size arrays aren't technically allowed, and MSVC in particular
+ // doesn't like them. We still need to declare these arrays to make
+ // other code compile. Since this is an uncommon case, we'll just declare
+ // them with size 1 and waste some space. Oh well.
+ printer->Print(
+ "static const int _offsets_[1];\n"
+ "\n"
+ "::google::protobuf::uint32 _has_bits_[1];\n");
+ }
+
+ printer->Print(
+ "\n"
+ "// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?\n"
+ "inline bool _has_bit(int index) const {\n"
+ " return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;\n"
+ "}\n"
+ "inline void _set_bit(int index) {\n"
+ " _has_bits_[index / 32] |= (1u << (index % 32));\n"
+ "}\n"
+ "inline void _clear_bit(int index) {\n"
+ " _has_bits_[index / 32] &= ~(1u << (index % 32));\n"
+ "}\n");
+
+ printer->Outdent();
+ printer->Print(vars, "};");
+}
+
+void MessageGenerator::
+GenerateInlineMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateInlineMethods(printer);
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+
+ GenerateFieldAccessorDefinitions(printer);
+}
+
+void MessageGenerator::
+GenerateDescriptorDeclarations(io::Printer* printer) {
+ printer->Print("const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n",
+ "name", classname_);
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateDescriptorDeclarations(printer);
+ }
+
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ printer->Print(
+ "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
+ "name", ClassName(descriptor_->enum_type(i), false));
+ }
+}
+
+void MessageGenerator::
+GenerateDescriptorInitializer(io::Printer* printer, int index) {
+ // TODO(kenton): Passing the index to this method is redundant; just use
+ // descriptor_->index() instead.
+ map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["index"] = SimpleItoa(index);
+
+ if (descriptor_->containing_type() == NULL) {
+ printer->Print(vars,
+ "$classname$_descriptor_ = file->message_type($index$);\n");
+ } else {
+ vars["parent"] = ClassName(descriptor_->containing_type(), false);
+ printer->Print(vars,
+ "$classname$_descriptor_ = "
+ "$parent$_descriptor_->nested_type($index$);\n");
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateDescriptorInitializer(printer, i);
+ }
+
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
+ }
+
+ // Register this message type with the message factory.
+ printer->Print(vars,
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+ " $classname$_descriptor_, &$classname$::default_instance());\n");
+}
+
+void MessageGenerator::
+GenerateClassMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ enum_generators_[i]->GenerateMethods(printer);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateClassMethods(printer);
+ printer->Print("\n");
+ printer->Print(kThinSeparator);
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ "const $classname$ $classname$::default_instance_;\n"
+ "\n",
+ "classname", classname_);
+
+ // Generate non-inline field definitions.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateNonInlineAccessorDefinitions(printer);
+ printer->Print("\n");
+ }
+
+ // Define extension identifiers.
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ extension_generators_[i]->GenerateDefinition(printer);
+ }
+
+ GenerateOffsets(printer);
+ printer->Print("\n");
+
+ GenerateStructors(printer);
+ printer->Print("\n");
+
+ if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ GenerateClear(printer);
+ printer->Print("\n");
+
+ GenerateMergeFromCodedStream(printer);
+ printer->Print("\n");
+
+ GenerateSerializeWithCachedSizes(printer);
+ printer->Print("\n");
+
+ GenerateByteSize(printer);
+ printer->Print("\n");
+
+ GenerateMergeFrom(printer);
+ printer->Print("\n");
+
+ GenerateCopyFrom(printer);
+ printer->Print("\n");
+
+ GenerateIsInitialized(printer);
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ "const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n"
+ " return descriptor();\n"
+ "}\n"
+ "\n"
+ "const ::google::protobuf::Message::Reflection*\n"
+ "$classname$::GetReflection() const {\n"
+ " return &_reflection_;\n"
+ "}\n"
+ "\n"
+ "::google::protobuf::Message::Reflection* $classname$::GetReflection() {\n"
+ " return &_reflection_;\n"
+ "}\n",
+ "classname", classname_);
+}
+
+void MessageGenerator::
+GenerateOffsets(io::Printer* printer) {
+ printer->Print(
+ "const int $classname$::_offsets_[$field_count$] = {\n",
+ "classname", classname_,
+ "field_count", SimpleItoa(max(1, descriptor_->field_count())));
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ printer->Print(
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
+ "classname", classname_,
+ "name", FieldName(field));
+ }
+
+ printer->Outdent();
+ printer->Print("};\n");
+}
+
+void MessageGenerator::
+GenerateInitializerList(io::Printer* printer) {
+ printer->Indent();
+ printer->Indent();
+
+ bool has_extensions = descriptor_->extension_range_count() > 0;
+ if (has_extensions) {
+ printer->Print(
+ "_extensions_(descriptor(),\n"
+ " ::google::protobuf::DescriptorPool::generated_pool(),\n"
+ " ::google::protobuf::MessageFactory::generated_factory()),\n");
+ }
+
+ printer->Print(
+ "_reflection_(descriptor(),\n"
+ " this, &default_instance_,\n"
+ " _offsets_, _has_bits_, $extensions$),\n"
+ "_cached_size_(0)",
+ "extensions", has_extensions ? "&_extensions_" : "NULL");
+
+ // Write the initializers for each field.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInitializer(printer);
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+}
+
+void MessageGenerator::
+GenerateStructors(io::Printer* printer) {
+ // Generate the default constructor.
+ printer->Print(
+ "$classname$::$classname$()\n"
+ " : ",
+ "classname", classname_);
+ GenerateInitializerList(printer);
+ printer->Print(" {\n"
+ " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n"
+ " if (this == &default_instance_) {\n");
+
+ // The default instance needs all of its embedded message pointers
+ // cross-linked to other default instances.
+ // TODO(kenton): Maybe all message fields (even for non-default messages)
+ // should be initialized to point at default instances rather than NULL?
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (!field->is_repeated() &&
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
+ "name", FieldName(field),
+ "type", ClassName(field->message_type(), true));
+ }
+ }
+ printer->Print(
+ " }\n"
+ "}\n"
+ "\n");
+
+ // Generate the copy constructor.
+ printer->Print(
+ "$classname$::$classname$(const $classname$& from)\n"
+ " : ",
+ "classname", classname_);
+ GenerateInitializerList(printer);
+ printer->Print(" {\n"
+ " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n"
+ " MergeFrom(from);\n"
+ "}\n"
+ "\n");
+
+ // Generate the destructor.
+ printer->Print(
+ "$classname$::~$classname$() {\n",
+ "classname", classname_);
+
+ printer->Indent();
+
+ // Write the destructors for each field.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateDestructorCode(printer);
+ }
+
+ printer->Print(
+ "if (this != &default_instance_) {\n");
+
+ // We need to delete all embedded messages.
+ // TODO(kenton): If we make unset messages point at default instances
+ // instead of NULL, then it would make sense to move this code into
+ // MessageFieldGenerator::GenerateDestructorCode().
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (!field->is_repeated() &&
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(" delete $name$_;\n",
+ "name", FieldName(field));
+ }
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ "}\n"
+ "\n"
+ "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
+ " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n"
+ " return $classname$_descriptor_;\n"
+ "}\n"
+ "\n"
+ "$classname$* $classname$::New() const {\n"
+ " return new $classname$;\n"
+ "}\n",
+ "classname", classname_,
+ "builddescriptorsname",
+ GlobalBuildDescriptorsName(descriptor_->file()->name()));
+}
+
+void MessageGenerator::
+GenerateClear(io::Printer* printer) {
+ printer->Print("void $classname$::Clear() {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ int last_index = -1;
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print("_extensions_.Clear();\n");
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (!field->is_repeated()) {
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(field->index());
+
+ // We can use the fact that _has_bits_ is a giant bitfield to our
+ // advantage: We can check up to 32 bits at a time for equality to
+ // zero, and skip the whole range if so. This can improve the speed
+ // of Clear() for messages which contain a very large number of
+ // optional fields of which only a few are used at a time. Here,
+ // we've chosen to check 8 bits at a time rather than 32.
+ if (i / 8 != last_index / 8 || last_index < 0) {
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print(vars,
+ "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
+ printer->Indent();
+ }
+ last_index = i;
+
+ // 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 should_check_bit =
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
+
+ if (should_check_bit) {
+ printer->Print(vars, "if (_has_bit($index$)) {\n");
+ printer->Indent();
+ }
+
+ field_generators_.get(field).GenerateClearingCode(printer);
+
+ if (should_check_bit) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ }
+
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
+ // Repeated fields don't use _has_bits_ so we clear them in a separate
+ // pass.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (field->is_repeated()) {
+ field_generators_.get(field).GenerateClearingCode(printer);
+ }
+ }
+
+ printer->Print(
+ "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"
+ "mutable_unknown_fields()->Clear();\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateMergeFrom(io::Printer* printer) {
+ // Generate the generalized MergeFrom (aka that which takes in the Message
+ // base class as a parameter).
+ printer->Print(
+ "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
+ " GOOGLE_CHECK_NE(&from, this);\n",
+ "classname", classname_);
+ printer->Indent();
+
+ if (descriptor_->field_count() > 0) {
+ // Cast the message to the proper type. If we find that the message is
+ // *not* of the proper type, we can still call Merge via the reflection
+ // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
+ // for each message.
+ printer->Print(
+ "const $classname$* source =\n"
+ " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
+ " &from);\n"
+ "if (source == NULL) {\n"
+ " ::google::protobuf::internal::ReflectionOps::Merge(\n"
+ " descriptor(), *from.GetReflection(), &_reflection_);\n"
+ "} else {\n"
+ " MergeFrom(*source);\n"
+ "}\n",
+ "classname", classname_);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
+ printer->Print(
+ "void $classname$::MergeFrom(const $classname$& from) {\n"
+ " GOOGLE_CHECK_NE(&from, this);\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // Merge Repeated fields. These fields do not require a
+ // check as we can simply iterate over them.
+ for (int i = 0; i < descriptor_->field_count(); ++i) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (field->is_repeated()) {
+ field_generators_.get(field).GenerateMergingCode(printer);
+ }
+ }
+
+ // Merge Optional and Required fields (after a _has_bit check).
+ int last_index = -1;
+
+ for (int i = 0; i < descriptor_->field_count(); ++i) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (!field->is_repeated()) {
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(field->index());
+
+ // See above in GenerateClear for an explanation of this.
+ if (i / 8 != last_index / 8 || last_index < 0) {
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print(vars,
+ "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
+ printer->Indent();
+ }
+
+ last_index = i;
+
+ printer->Print(vars,
+ "if (from._has_bit($index$)) {\n");
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergingCode(printer);
+
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
+ }
+
+ printer->Print(
+ "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateCopyFrom(io::Printer* printer) {
+ // Generate the generalized CopyFrom (aka that which takes in the Message
+ // base class as a parameter).
+ printer->Print(
+ "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ printer->Print(
+ "if (&from == this) return;\n"
+ "Clear();\n"
+ "MergeFrom(from);\n");
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Generate the class-specific CopyFrom.
+ printer->Print(
+ "void $classname$::CopyFrom(const $classname$& from) {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ printer->Print(
+ "if (&from == this) return;\n"
+ "Clear();\n"
+ "MergeFrom(from);\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) {
+ if (descriptor_->options().message_set_wire_format()) {
+ // For message_set_wire_format, we don't generate a parser, for two
+ // reasons:
+ // - WireFormat already needs to special-case this, and we'd like to
+ // avoid having multiple implementations of MessageSet wire format
+ // lying around the code base.
+ // - All fields are extensions, and extension parsing falls back to
+ // reflection anyway, so it wouldn't be any faster.
+ printer->Print(
+ "bool $classname$::MergePartialFromCodedStream(\n"
+ " ::google::protobuf::io::CodedInputStream* input) {\n"
+ " return ::google::protobuf::internal::WireFormat::ParseAndMergePartial(\n"
+ " descriptor(), input, &_reflection_);\n"
+ "}\n",
+ "classname", classname_);
+ return;
+ }
+
+ printer->Print(
+ "bool $classname$::MergePartialFromCodedStream(\n"
+ " ::google::protobuf::io::CodedInputStream* input) {\n"
+ "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n"
+ " ::google::protobuf::uint32 tag;\n"
+ " while ((tag = input->ReadTag()) != 0) {\n",
+ "classname", classname_);
+
+ printer->Indent();
+ printer->Indent();
+
+ if (descriptor_->field_count() > 0) {
+ // We don't even want to print the switch() if we have no fields because
+ // MSVC dislikes switch() statements that contain only a default value.
+
+ // Note: If we just switched on the tag rather than the field number, we
+ // could avoid the need for the if() to check the wire type at the beginning
+ // of each case. However, this is actually a bit slower in practice as it
+ // creates a jump table that is 8x larger and sparser, and meanwhile the
+ // if()s are highly predictable.
+ printer->Print(
+ "switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {\n");
+
+ printer->Indent();
+
+ scoped_array<const FieldDescriptor*> ordered_fields(
+ SortFieldsByNumber(descriptor_));
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+
+ PrintFieldComment(printer, field);
+
+ printer->Print(
+ "case $number$: {\n"
+ " if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=\n"
+ " ::google::protobuf::internal::WireFormat::WIRETYPE_$wiretype$) {\n"
+ " goto handle_uninterpreted;\n"
+ " }\n",
+ "number", SimpleItoa(field->number()),
+ "wiretype", kWireTypeNames[
+ WireFormat::WireTypeForFieldType(field->type())]);
+
+ if (i > 0 || field->is_repeated()) {
+ printer->Print(
+ " parse_$name$:\n",
+ "name", field->name());
+ }
+
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergeFromCodedStream(printer);
+
+ // switch() is slow since it can't be predicted well. Insert some if()s
+ // here that attempt to predict the next tag.
+ if (field->is_repeated()) {
+ // Expect repeats of this field.
+ printer->Print(
+ "if (input->ExpectTag($tag$)) goto parse_$name$;\n",
+ "tag", SimpleItoa(WireFormat::MakeTag(field)),
+ "name", field->name());
+ }
+
+ if (i + 1 < descriptor_->field_count()) {
+ // Expect the next field in order.
+ const FieldDescriptor* next_field = ordered_fields[i + 1];
+ printer->Print(
+ "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
+ "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+ "next_name", next_field->name());
+ } else {
+ // Expect EOF.
+ // TODO(kenton): Expect group end-tag?
+ printer->Print(
+ "if (input->ExpectAtEnd()) return true;\n");
+ }
+
+ printer->Print(
+ "break;\n");
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ printer->Print(
+ "default: {\n"
+ "handle_uninterpreted:\n");
+ printer->Indent();
+ }
+
+ // Is this an end-group tag? If so, this must be the end of the message.
+ printer->Print(
+ "if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==\n"
+ " ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {\n"
+ " return true;\n"
+ "}\n");
+
+ // Handle extension ranges.
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "if (");
+ for (int i = 0; i < descriptor_->extension_range_count(); i++) {
+ const Descriptor::ExtensionRange* range =
+ descriptor_->extension_range(i);
+ if (i > 0) printer->Print(" &&\n ");
+
+ uint32 start_tag = WireFormat::MakeTag(
+ range->start, static_cast<WireFormat::WireType>(0));
+ uint32 end_tag = WireFormat::MakeTag(
+ range->end, static_cast<WireFormat::WireType>(0));
+
+ if (range->end > FieldDescriptor::kMaxNumber) {
+ printer->Print(
+ "($start$u <= tag)",
+ "start", SimpleItoa(start_tag));
+ } else {
+ printer->Print(
+ "($start$u <= tag && tag < $end$u)",
+ "start", SimpleItoa(start_tag),
+ "end", SimpleItoa(end_tag));
+ }
+ }
+ printer->Print(") {\n"
+ " DO_(_extensions_.ParseField(tag, input, &_reflection_));\n"
+ " continue;\n"
+ "}\n");
+ }
+
+ // We really don't recognize this tag. Skip it.
+ printer->Print(
+ "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
+ " input, tag, mutable_unknown_fields()));\n");
+
+ if (descriptor_->field_count() > 0) {
+ printer->Print("break;\n");
+ printer->Outdent();
+ printer->Print("}\n"); // default:
+ printer->Outdent();
+ printer->Print("}\n"); // switch
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // while
+ " return true;\n"
+ "#undef DO_\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+ io::Printer* printer, const FieldDescriptor* field) {
+ PrintFieldComment(printer, field);
+
+ if (field->is_repeated()) {
+ printer->Print(
+ "for (int i = 0; i < $name$_.size(); i++) {\n",
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "if (_has_bit($index$)) {\n",
+ "index", SimpleItoa(field->index()));
+ }
+
+ printer->Indent();
+
+ field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void MessageGenerator::GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range) {
+ map<string, string> vars;
+ vars["start"] = SimpleItoa(range->start);
+ vars["end"] = SimpleItoa(range->end);
+ printer->Print(vars,
+ "// Extension range [$start$, $end$)\n"
+ "DO_(_extensions_.SerializeWithCachedSizes(\n"
+ " $start$, $end$, &_reflection_, output));\n\n");
+}
+
+void MessageGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) {
+ printer->Print(
+ "bool $classname$::SerializeWithCachedSizes(\n"
+ " ::google::protobuf::io::CodedOutputStream* output) const {\n"
+ "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n",
+ "classname", classname_);
+ printer->Indent();
+
+ scoped_array<const FieldDescriptor*> ordered_fields(
+ SortFieldsByNumber(descriptor_));
+
+ vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+ sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeSorter());
+
+ // Merge the fields and the extension ranges, both sorted by field number.
+ int i, j;
+ for (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, ordered_fields[i++]);
+ } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) {
+ GenerateSerializeOneField(printer, ordered_fields[i++]);
+ } else {
+ GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+ }
+ }
+
+ printer->Print("if (!unknown_fields().empty()) {\n");
+ printer->Indent();
+ if (descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
+ " unknown_fields(), output));\n");
+ } else {
+ printer->Print(
+ "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+ " unknown_fields(), output));\n");
+ }
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "return true;\n");
+
+ printer->Outdent();
+ printer->Print(
+ "#undef DO_\n"
+ "}\n");
+}
+
+void MessageGenerator::
+GenerateByteSize(io::Printer* printer) {
+ printer->Print(
+ "int $classname$::ByteSize() const {\n",
+ "classname", classname_);
+ printer->Indent();
+ printer->Print(
+ "int total_size = 0;\n"
+ "\n");
+
+ int last_index = -1;
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (!field->is_repeated()) {
+ // See above in GenerateClear for an explanation of this.
+ // TODO(kenton): Share code? Unclear how to do so without
+ // over-engineering.
+ if ((i / 8) != (last_index / 8) ||
+ last_index < 0) {
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print(
+ "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
+ "index", SimpleItoa(field->index()));
+ printer->Indent();
+ }
+ last_index = i;
+
+ PrintFieldComment(printer, field);
+
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateByteSize(printer);
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+ }
+ }
+
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
+ // Repeated fields don't use _has_bits_ so we count them in a separate
+ // pass.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (field->is_repeated()) {
+ PrintFieldComment(printer, field);
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Print("\n");
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "total_size += _extensions_.ByteSize(&_reflection_);\n"
+ "\n");
+ }
+
+ printer->Print("if (!unknown_fields().empty()) {\n");
+ printer->Indent();
+ if (descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::ComputeUnknownMessageSetItemsSize(\n"
+ " unknown_fields());\n");
+ } else {
+ printer->Print(
+ "total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+ " unknown_fields());\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+
+ // We update _cached_size_ even though this is a const method. In theory,
+ // this is not thread-compatible, because concurrent writes have undefined
+ // results. In practice, since any concurrent writes will be writing the
+ // exact same value, it works on all common processors. In a future version
+ // of C++, _cached_size_ should be made into an atomic<int>.
+ printer->Print(
+ "_cached_size_ = total_size;\n"
+ "return total_size;\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateIsInitialized(io::Printer* printer) {
+ printer->Print(
+ "bool $classname$::IsInitialized() const {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // Check that all required fields in this message are set. We can do this
+ // most efficiently by checking 32 "has bits" at a time.
+ int has_bits_array_size = (descriptor_->field_count() + 31) / 32;
+ for (int i = 0; i < has_bits_array_size; i++) {
+ uint32 mask = 0;
+ for (int bit = 0; bit < 32; bit++) {
+ int index = i * 32 + bit;
+ if (index >= descriptor_->field_count()) break;
+ const FieldDescriptor* field = descriptor_->field(index);
+
+ if (field->is_required()) {
+ mask |= 1 << bit;
+ }
+ }
+
+ if (mask != 0) {
+ char buffer[kFastToBufferSize];
+ printer->Print(
+ "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
+ "i", SimpleItoa(i),
+ "mask", FastHex32ToBuffer(mask, buffer));
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ printer->Print("\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ HasRequiredFields(field->message_type())) {
+ if (field->is_repeated()) {
+ printer->Print(
+ "for (int i = 0; i < $name$_size(); i++) {\n"
+ " if (!this->$name$(i).IsInitialized()) return false;\n"
+ "}\n",
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "if (has_$name$()) {\n"
+ " if (!this->$name$().IsInitialized()) return false;\n"
+ "}\n",
+ "name", FieldName(field));
+ }
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "\n"
+ "if (!_extensions_.IsInitialized()) return false;");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " return true;\n"
+ "}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
new file mode 100644
index 00000000..904e0487
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -0,0 +1,125 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+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.
+ explicit MessageGenerator(const Descriptor* descriptor,
+ const string& dllexport_decl);
+ ~MessageGenerator();
+
+ // Header stuff.
+
+ // Generate foward declarations for this class and all its nested types.
+ void GenerateForwardDeclaration(io::Printer* printer);
+
+ // Generate definitions of all nested enums (must come before class
+ // definitions because those classes use the enums definitions).
+ void GenerateEnumDefinitions(io::Printer* printer);
+
+ // 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 code which declares all the global descriptor pointers which
+ // will be initialized by the methods below.
+ void GenerateDescriptorDeclarations(io::Printer* printer);
+
+ // Generate code that initializes the global variable storing the message's
+ // descriptor.
+ void GenerateDescriptorInitializer(io::Printer* printer, int index);
+
+ // Generate all non-inline methods for this class.
+ void GenerateClassMethods(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.
+ void GenerateOffsets(io::Printer* printer);
+
+ // Generate constructors and destructor.
+ void GenerateStructors(io::Printer* printer);
+
+ // Generate the member initializer list for the constructors. The member
+ // initializer list is shared between the default constructor and the copy
+ // constructor.
+ void GenerateInitializerList(io::Printer* printer);
+
+ // Generate standard Message methods.
+ void GenerateClear(io::Printer* printer);
+ void GenerateMergeFromCodedStream(io::Printer* printer);
+ void GenerateSerializeWithCachedSizes(io::Printer* printer);
+ void GenerateByteSize(io::Printer* printer);
+ void GenerateMergeFrom(io::Printer* printer);
+ void GenerateCopyFrom(io::Printer* printer);
+ void GenerateIsInitialized(io::Printer* printer);
+
+ // Helpers for GenerateSerializeWithCachedSizes().
+ void GenerateSerializeOneField(io::Printer* printer,
+ const FieldDescriptor* field);
+ void GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+ const Descriptor* descriptor_;
+ string classname_;
+ string dllexport_decl_;
+ FieldGeneratorMap field_generators_;
+ scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
+ scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
+ scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+
+ 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/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
new file mode 100644
index 00000000..501ca569
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -0,0 +1,229 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_message_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["name"] = FieldName(descriptor);
+ (*variables)["type"] = ClassName(descriptor->message_type(), true);
+ (*variables)["index"] = SimpleItoa(descriptor->index());
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+ (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+}
+
+} // namespace
+
+// ===================================================================
+
+MessageFieldGenerator::
+MessageFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_, "$type$* $name$_;\n");
+}
+
+void MessageFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const $type$& $name$() const;\n"
+ "inline $type$* mutable_$name$();\n");
+}
+
+void MessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const $type$& $classname$::$name$() const {\n"
+ " return $name$_ != NULL ? *$name$_ : *default_instance_.$name$_;\n"
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$() {\n"
+ " _set_bit($index$);\n"
+ " if ($name$_ == NULL) $name$_ = new $type$;\n"
+ " return $name$_;\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($name$_ != NULL) $name$_->$type$::Clear();\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "mutable_$name$()->$type$::MergeFrom(from.$name$());\n");
+}
+
+void MessageFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ printer->Print(variables_, ",\n$name$_(NULL)");
+}
+
+void MessageFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
+ " input, mutable_$name$()));\n");
+ } else {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
+ "$number$, input, mutable_$name$()));\n");
+ }
+}
+
+void MessageFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
+ "$number$, this->$name$(), output));\n");
+}
+
+void MessageFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ +\n"
+ " ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
+ " this->$name$());\n");
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const;\n"
+ "inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$();\n"
+ "inline const $type$& $name$(int index) const;\n"
+ "inline $type$* mutable_$name$(int index);\n"
+ "inline $type$* add_$name$();\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+ "$classname$::$name$() const {\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ "$classname$::mutable_$name$() {\n"
+ " return &$name$_;\n"
+ "}\n"
+ "inline const $type$& $classname$::$name$(int index) const {\n"
+ " return $name$_.Get(index);\n"
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$(int index) {\n"
+ " return $name$_.Mutable(index);\n"
+ "}\n"
+ "inline $type$* $classname$::add_$name$() {\n"
+ " return $name$_.Add();\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ // Not needed for repeated fields.
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
+ " input, add_$name$()));\n");
+ } else {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
+ "$number$, input, add_$name$()));\n");
+ }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
+ "$number$, this->$name$(i), output));\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * $name$_size();\n"
+ "for (int i = 0; i < $name$_size(); i++) {\n"
+ " total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
+ " this->$name$(i));\n"
+ "}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
new file mode 100644
index 00000000..a2be6b65
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+ ~MessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedMessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ 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/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
new file mode 100644
index 00000000..312ed031
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -0,0 +1,294 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+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 WireFormat::kFixed32Size;
+ case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
+ case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
+ case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
+ case FieldDescriptor::TYPE_FLOAT : return WireFormat::kFloatSize;
+ case FieldDescriptor::TYPE_DOUBLE : return WireFormat::kDoubleSize;
+
+ case FieldDescriptor::TYPE_BOOL : return WireFormat::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;
+}
+
+string DefaultValue(const FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return SimpleItoa(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return SimpleItoa(field->default_value_uint32()) + "u";
+ case FieldDescriptor::CPPTYPE_INT64:
+ return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return SimpleDtoa(field->default_value_double());
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return SimpleFtoa(field->default_value_float());
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "true" : "false";
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ GOOGLE_LOG(FATAL) << "Shouldn't get here.";
+ return "";
+ }
+ // 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.)
+ return "";
+}
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["name"] = FieldName(descriptor);
+ (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
+ (*variables)["default"] = DefaultValue(descriptor);
+ (*variables)["index"] = SimpleItoa(descriptor->index());
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+ (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+
+ int fixed_size = FixedSize(descriptor->type());
+ if (fixed_size != -1) {
+ (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+ }
+}
+
+} // namespace
+
+// ===================================================================
+
+PrimitiveFieldGenerator::
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+void PrimitiveFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_, "$type$ $name$_;\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline $type$ $name$() const;\n"
+ "inline void set_$name$($type$ value);\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline $type$ $classname$::$name$() const {\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline void $classname$::set_$name$($type$ value) {\n"
+ " _set_bit($index$);\n"
+ " $name$_ = value;\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "set_$name$(from.$name$());\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ printer->Print(variables_, ",\n$name$_($default$)");
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
+ " input, &$name$_));\n"
+ "_set_bit($index$);\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(), output));\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ int fixed_size = FixedSize(descriptor_->type());
+ if (fixed_size == -1) {
+ printer->Print(variables_,
+ "total_size += $tag_size$ +\n"
+ " ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+ " this->$name$());\n");
+ } else {
+ printer->Print(variables_,
+ "total_size += $tag_size$ + $fixed_size$;\n");
+ }
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const;\n"
+ "inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$();\n"
+ "inline $type$ $name$(int index) const;\n"
+ "inline void set_$name$(int index, $type$ value);\n"
+ "inline void add_$name$($type$ value);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+ "$classname$::$name$() const {\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+ "$classname$::mutable_$name$() {\n"
+ " return &$name$_;\n"
+ "}\n"
+ "inline $type$ $classname$::$name$(int index) const {\n"
+ " return $name$_.Get(index);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+ " $name$_.Set(index, value);\n"
+ "}\n"
+ "inline void $classname$::add_$name$($type$ value) {\n"
+ " $name$_.Add(value);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ // Not needed for repeated fields.
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$ value;\n"
+ "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(input, &value));\n"
+ "add_$name$(value);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(i), output));\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ int fixed_size = FixedSize(descriptor_->type());
+ if (fixed_size == -1) {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * $name$_size();\n"
+ "for (int i = 0; i < $name$_size(); i++) {\n"
+ " total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+ " this->$name$(i));\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "total_size += ($tag_size$ + $fixed_size$) * $name$_size();\n");
+ }
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
new file mode 100644
index 00000000..832b2411
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ ~PrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ 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/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
new file mode 100644
index 00000000..124f3b43
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -0,0 +1,318 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_service.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
+ const string& dllexport_decl)
+ : descriptor_(descriptor) {
+ vars_["classname"] = descriptor_->name();
+ vars_["full_name"] = descriptor_->full_name();
+ if (dllexport_decl.empty()) {
+ vars_["dllexport"] = "";
+ } else {
+ vars_["dllexport"] = dllexport_decl + " ";
+ }
+}
+
+ServiceGenerator::~ServiceGenerator() {}
+
+void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
+ // Forward-declare the stub type.
+ printer->Print(vars_,
+ "class $classname$_Stub;\n"
+ "\n");
+
+ GenerateInterface(printer);
+ GenerateStubDefinition(printer);
+}
+
+void ServiceGenerator::GenerateInterface(io::Printer* printer) {
+ printer->Print(vars_,
+ "class $dllexport$$classname$ : public ::google::protobuf::Service {\n"
+ " protected:\n"
+ " // This class should be treated as an abstract interface.\n"
+ " inline $classname$() {};\n"
+ " public:\n"
+ " virtual ~$classname$();\n");
+ printer->Indent();
+
+ printer->Print(vars_,
+ "\n"
+ "typedef $classname$_Stub Stub;\n"
+ "\n"
+ "static const ::google::protobuf::ServiceDescriptor* descriptor();\n"
+ "\n");
+
+ GenerateMethodSignatures(VIRTUAL, printer);
+
+ printer->Print(
+ "\n"
+ "// implements Service ----------------------------------------------\n"
+ "\n"
+ "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n"
+ "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
+ " ::google::protobuf::RpcController* controller,\n"
+ " const ::google::protobuf::Message* request,\n"
+ " ::google::protobuf::Message* response,\n"
+ " ::google::protobuf::Closure* done);\n"
+ "const ::google::protobuf::Message& GetRequestPrototype(\n"
+ " const ::google::protobuf::MethodDescriptor* method) const;\n"
+ "const ::google::protobuf::Message& GetResponsePrototype(\n"
+ " const ::google::protobuf::MethodDescriptor* method) const;\n");
+
+ printer->Outdent();
+ printer->Print(vars_,
+ "\n"
+ " private:\n"
+ " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
+ "};\n"
+ "\n");
+}
+
+void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
+ printer->Print(vars_,
+ "class $dllexport$$classname$_Stub : public $classname$ {\n"
+ " public:\n");
+
+ printer->Indent();
+
+ printer->Print(vars_,
+ "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n"
+ "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n"
+ " ::google::protobuf::Service::ChannelOwnership ownership);\n"
+ "~$classname$_Stub();\n"
+ "\n"
+ "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n"
+ "\n"
+ "// implements $classname$ ------------------------------------------\n"
+ "\n");
+
+ GenerateMethodSignatures(NON_VIRTUAL, printer);
+
+ printer->Outdent();
+ printer->Print(vars_,
+ " private:\n"
+ " ::google::protobuf::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);
+ map<string, string> sub_vars;
+ sub_vars["name"] = method->name();
+ sub_vars["input_type"] = ClassName(method->input_type(), true);
+ sub_vars["output_type"] = ClassName(method->output_type(), true);
+ sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : "";
+
+ printer->Print(sub_vars,
+ "$virtual$void $name$(::google::protobuf::RpcController* controller,\n"
+ " const $input_type$* request,\n"
+ " $output_type$* response,\n"
+ " ::google::protobuf::Closure* done);\n");
+ }
+}
+
+// ===================================================================
+
+void ServiceGenerator::GenerateDescriptorInitializer(
+ io::Printer* printer, int index) {
+ map<string, string> vars;
+ vars["classname"] = descriptor_->name();
+ vars["index"] = SimpleItoa(index);
+
+ printer->Print(vars,
+ "$classname$_descriptor_ = file->service($index$);\n");
+}
+
+// ===================================================================
+
+void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
+ printer->Print(vars_,
+ "$classname$::~$classname$() {}\n"
+ "\n"
+ "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n"
+ " return $classname$_descriptor_;\n"
+ "}\n"
+ "\n"
+ "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n"
+ " return $classname$_descriptor_;\n"
+ "}\n"
+ "\n");
+
+ // Generate methods of the interface.
+ GenerateNotImplementedMethods(printer);
+ GenerateCallMethod(printer);
+ GenerateGetPrototype(REQUEST, printer);
+ GenerateGetPrototype(RESPONSE, printer);
+
+ // Generate stub implementation.
+ printer->Print(vars_,
+ "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n"
+ " : channel_(channel), owns_channel_(false) {}\n"
+ "$classname$_Stub::$classname$_Stub(\n"
+ " ::google::protobuf::RpcChannel* channel,\n"
+ " ::google::protobuf::Service::ChannelOwnership ownership)\n"
+ " : channel_(channel),\n"
+ " owns_channel_(ownership == ::google::protobuf::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);
+ map<string, string> sub_vars;
+ sub_vars["classname"] = descriptor_->name();
+ sub_vars["name"] = method->name();
+ sub_vars["index"] = SimpleItoa(i);
+ sub_vars["input_type"] = ClassName(method->input_type(), true);
+ sub_vars["output_type"] = ClassName(method->output_type(), true);
+
+ printer->Print(sub_vars,
+ "void $classname$::$name$(::google::protobuf::RpcController* controller,\n"
+ " const $input_type$* request,\n"
+ " $output_type$* response,\n"
+ " ::google::protobuf::Closure* done) {\n"
+ " controller->SetFailed(\"Method $name$() not implemented.\");\n"
+ " done->Run();\n"
+ "}\n"
+ "\n");
+ }
+}
+
+void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
+ printer->Print(vars_,
+ "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
+ " ::google::protobuf::RpcController* controller,\n"
+ " const ::google::protobuf::Message* request,\n"
+ " ::google::protobuf::Message* response,\n"
+ " ::google::protobuf::Closure* done) {\n"
+ " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
+ " switch(method->index()) {\n");
+
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ map<string, string> sub_vars;
+ sub_vars["name"] = method->name();
+ sub_vars["index"] = SimpleItoa(i);
+ sub_vars["input_type"] = ClassName(method->input_type(), true);
+ sub_vars["output_type"] = ClassName(method->output_type(), true);
+
+ // Note: ::google::protobuf::down_cast does not work here because it only works on pointers,
+ // not references.
+ printer->Print(sub_vars,
+ " case $index$:\n"
+ " $name$(controller,\n"
+ " ::google::protobuf::down_cast<const $input_type$*>(request),\n"
+ " ::google::protobuf::down_cast< $output_type$*>(response),\n"
+ " done);\n"
+ " break;\n");
+ }
+
+ printer->Print(vars_,
+ " 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) {
+ if (which == REQUEST) {
+ printer->Print(vars_,
+ "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
+ } else {
+ printer->Print(vars_,
+ "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n");
+ }
+
+ printer->Print(vars_,
+ " const ::google::protobuf::MethodDescriptor* method) const {\n"
+ " GOOGLE_DCHECK_EQ(method->service(), $classname$_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();
+
+ map<string, string> sub_vars;
+ sub_vars["index"] = SimpleItoa(i);
+ sub_vars["type"] = ClassName(type, true);
+
+ printer->Print(sub_vars,
+ " case $index$:\n"
+ " return $type$::default_instance();\n");
+ }
+
+ printer->Print(vars_,
+ " default:\n"
+ " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
+ " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
+ " }\n"
+ "}\n"
+ "\n");
+}
+
+void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ map<string, string> sub_vars;
+ sub_vars["classname"] = descriptor_->name();
+ sub_vars["name"] = method->name();
+ sub_vars["index"] = SimpleItoa(i);
+ sub_vars["input_type"] = ClassName(method->input_type(), true);
+ sub_vars["output_type"] = ClassName(method->output_type(), true);
+
+ printer->Print(sub_vars,
+ "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n"
+ " const $input_type$* request,\n"
+ " $output_type$* response,\n"
+ " ::google::protobuf::Closure* done) {\n"
+ " channel_->CallMethod($classname$_descriptor_->method($index$),\n"
+ " controller, request, response, done);\n"
+ "}\n");
+ }
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h
new file mode 100644
index 00000000..bccb64e4
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_service.h
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class ServiceGenerator {
+ public:
+ // See generator.cc for the meaning of dllexport_decl.
+ explicit ServiceGenerator(const ServiceDescriptor* descriptor,
+ const string& dllexport_decl);
+ ~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 code that initializes the global variable storing the service's
+ // descriptor.
+ void GenerateDescriptorInitializer(io::Printer* printer, int index);
+
+ // 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_;
+ map<string, string> vars_;
+
+ 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/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
new file mode 100644
index 00000000..de59ac87
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -0,0 +1,336 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/cpp_string_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetStringVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["name"] = FieldName(descriptor);
+ (*variables)["default"] =
+ "\"" + CEscape(descriptor->default_value_string()) + "\"";
+ (*variables)["index"] = SimpleItoa(descriptor->index());
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+ (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+}
+
+} // namespace
+
+// ===================================================================
+
+StringFieldGenerator::
+StringFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetStringVariables(descriptor, &variables_);
+}
+
+StringFieldGenerator::~StringFieldGenerator() {}
+
+void StringFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "::std::string* $name$_;\n"
+ "static const ::std::string _default_$name$_;\n");
+}
+
+void StringFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ // 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.
+ if (descriptor_->options().has_ctype()) {
+ printer->Outdent();
+ printer->Print(
+ " private:\n"
+ " // Hidden due to unknown ctype option.\n");
+ printer->Indent();
+ }
+
+ printer->Print(variables_,
+ "inline const ::std::string& $name$() const;\n"
+ "inline void set_$name$(const ::std::string& value);\n"
+ "inline void set_$name$(const char* value);\n");
+
+ printer->Print(variables_,
+ "inline ::std::string* mutable_$name$();\n");
+
+ if (descriptor_->options().has_ctype()) {
+ printer->Outdent();
+ printer->Print(" public:\n");
+ printer->Indent();
+ }
+}
+
+void StringFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::std::string& $classname$::$name$() const {\n"
+ " return *$name$_;\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ " _set_bit($index$);\n"
+ " if ($name$_ == &_default_$name$_) {\n"
+ " $name$_ = new ::std::string;\n"
+ " }\n"
+ " $name$_->assign(value);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " _set_bit($index$);\n"
+ " if ($name$_ == &_default_$name$_) {\n"
+ " $name$_ = new ::std::string;\n"
+ " }\n"
+ " $name$_->assign(value);\n"
+ "}\n");
+ printer->Print(variables_,
+ "inline ::std::string* $classname$::mutable_$name$() {\n"
+ " _set_bit($index$);\n"
+ " if ($name$_ == &_default_$name$_) {\n");
+ if (descriptor_->has_default_value()) {
+ printer->Print(variables_,
+ " $name$_ = new ::std::string(_default_$name$_);\n");
+ } else {
+ printer->Print(variables_,
+ " $name$_ = new ::std::string;\n");
+ }
+ printer->Print(variables_,
+ " }\n"
+ " return $name$_;\n"
+ "}\n");
+}
+
+void StringFieldGenerator::
+GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
+ if (descriptor_->has_default_value()) {
+ printer->Print(variables_,
+ "const ::std::string $classname$::_default_$name$_($default$);");
+ } else {
+ printer->Print(variables_,
+ "const ::std::string $classname$::_default_$name$_;");
+ }
+}
+
+void StringFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ if (descriptor_->has_default_value()) {
+ printer->Print(variables_,
+ "if ($name$_ != &_default_$name$_) {\n"
+ " $name$_->assign(_default_$name$_);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if ($name$_ != &_default_$name$_) {\n"
+ " $name$_->clear();\n"
+ "}\n");
+ }
+}
+
+void StringFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "set_$name$(from.$name$());\n");
+}
+
+void StringFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ printer->Print(variables_,
+ ",\n$name$_(const_cast< ::std::string*>(&_default_$name$_))");
+}
+
+void StringFieldGenerator::
+GenerateDestructorCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($name$_ != &_default_$name$_) {\n"
+ " delete $name$_;\n"
+ "}\n");
+}
+
+void StringFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
+ "input, mutable_$name$()));\n");
+}
+
+void StringFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(), output));\n");
+}
+
+void StringFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ +\n"
+ " ::google::protobuf::internal::WireFormat::$declared_type$Size(this->$name$());\n");
+}
+
+// ===================================================================
+
+RepeatedStringFieldGenerator::
+RepeatedStringFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetStringVariables(descriptor, &variables_);
+}
+
+RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
+
+void RepeatedStringFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "::google::protobuf::RepeatedPtrField< ::std::string> $name$_;\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ // See comment above about unknown ctypes.
+ if (descriptor_->options().has_ctype()) {
+ printer->Outdent();
+ printer->Print(
+ " private:\n"
+ " // Hidden due to unknown ctype option.\n");
+ printer->Indent();
+ }
+
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const;\n"
+ "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$();\n"
+ "inline const ::std::string& $name$(int index) const;\n"
+ "inline ::std::string* mutable_$name$(int index);\n"
+ "inline void set_$name$(int index, const ::std::string& value);\n"
+ "inline void set_$name$(int index, const char* value);\n"
+ "inline ::std::string* add_$name$();\n"
+ "inline void add_$name$(const ::std::string& value);\n"
+ "inline void add_$name$(const char* value);\n");
+
+ if (descriptor_->options().has_ctype()) {
+ printer->Outdent();
+ printer->Print(" public:\n");
+ printer->Indent();
+ }
+}
+
+void RepeatedStringFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
+ "$classname$::$name$() const {\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
+ "$classname$::mutable_$name$() {\n"
+ " return &$name$_;\n"
+ "}\n"
+ "inline const ::std::string& $classname$::$name$(int index) const {\n"
+ " return $name$_.Get(index);\n"
+ "}\n"
+ "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+ " return $name$_.Mutable(index);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+ " $name$_.Mutable(index)->assign(value);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(int index, const char* value) {\n"
+ " $name$_.Mutable(index)->assign(value);\n"
+ "}\n"
+ "inline ::std::string* $classname$::add_$name$() {\n"
+ " return $name$_.Add();\n"
+ "}\n"
+ "inline void $classname$::add_$name$(const ::std::string& value) {\n"
+ " $name$_.Add()->assign(value);\n"
+ "}\n"
+ "inline void $classname$::add_$name$(const char* value) {\n"
+ " $name$_.Add()->assign(value);\n"
+ "}\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateInitializer(io::Printer* printer) const {
+ // Not needed for repeated fields.
+}
+
+void RepeatedStringFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
+ " input, add_$name$()));\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(i), output));\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * $name$_size();\n"
+ "for (int i = 0; i < $name$_size(); i++) {\n"
+ " total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+ " this->$name$(i));\n"
+ "}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
new file mode 100644
index 00000000..44ffd18c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/cpp_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class StringFieldGenerator : public FieldGenerator {
+ public:
+ explicit StringFieldGenerator(const FieldDescriptor* descriptor);
+ ~StringFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateDestructorCode(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
+};
+
+class RepeatedStringFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedStringFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateClearingCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateInitializer(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ 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/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
new file mode 100644
index 00000000..ee0499bf
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+
+// 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;
+
+ 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;
+
+ // The generator used to #define a macro called "DO" inside the .cc file.
+ message DO {}
+ optional DO do = 32;
+
+ extensions 1000 to max;
+}
+
+message DummyMessage {}
+
+service TestConflictingMethodNames {
+ rpc Closure(DummyMessage) returns (DummyMessage);
+}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
new file mode 100644
index 00000000..8253242b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -0,0 +1,835 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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
+// google/protobuf/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 <vector>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_optimize_for.pb.h>
+#include <google/protobuf/unittest_embed_optimize_for.pb.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+
+#include <google/protobuf/stubs/common.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 compiler {
+namespace cpp {
+
+namespace {
+
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename, int line, int column,
+ const string& message) {
+ strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
+ filename, line, column, message);
+ }
+};
+
+// 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(GeneratedDescriptorTest, IdenticalDescriptors) {
+ const FileDescriptor* generated_descriptor =
+ unittest::TestAllTypes::descriptor()->file();
+
+ // Set up the Importer.
+ MockErrorCollector error_collector;
+ DiskSourceTree source_tree;
+ source_tree.MapPath("", TestSourceDir());
+ Importer importer(&source_tree, &error_collector);
+
+ // Import (parse) unittest.proto.
+ const FileDescriptor* parsed_descriptor =
+ importer.Import("google/protobuf/unittest.proto");
+ EXPECT_EQ("", error_collector.text_);
+ ASSERT_TRUE(parsed_descriptor != NULL);
+
+ // Test that descriptors are generated correctly by converting them to
+ // FileDescriptorProtos and comparing.
+ FileDescriptorProto generated_decsriptor_proto, parsed_descriptor_proto;
+ generated_descriptor->CopyTo(&generated_decsriptor_proto);
+ parsed_descriptor->CopyTo(&parsed_descriptor_proto);
+
+ EXPECT_EQ(parsed_descriptor_proto.DebugString(),
+ generated_decsriptor_proto.DebugString());
+}
+
+// ===================================================================
+
+TEST(GeneratedMessageTest, 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(GeneratedMessageTest, 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(GeneratedMessageTest, 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(GeneratedMessageTest, 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);
+
+ // Unlike with the defaults test, we do NOT expect that requesting embedded
+ // messages will return a pointer to the default instance. Instead, they
+ // should return the objects that were created when mutable_blah() was
+ // called.
+ 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(GeneratedMessageTest, 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 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(GeneratedMessageTest, CopyFrom) {
+ unittest::TestAllTypes message1, message2;
+ string data;
+
+ TestUtil::SetAllFields(&message1);
+ message2.CopyFrom(message1);
+ TestUtil::ExpectAllFieldsSet(message2);
+
+ // Copying from self should be a no-op.
+ message2.CopyFrom(message2);
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GeneratedMessageTest, CopyConstructor) {
+ unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+
+ unittest::TestAllTypes message2(message1);
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GeneratedMessageTest, CopyAssignmentOperator) {
+ unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+
+ unittest::TestAllTypes message2;
+ message2 = message1;
+ TestUtil::ExpectAllFieldsSet(message2);
+
+ // Make sure that self-assignment does something sane.
+ message2 = message2;
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GeneratedMessageTest, 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(GeneratedMessageTest, 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;
+ scoped_ptr<Message> message1;
+ message1.reset(factory.GetPrototype(
+ unittest::TestAllTypes::descriptor())->New());
+
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+ reflection_tester.SetAllFieldsViaReflection(message1->GetReflection());
+
+ message2.CopyFrom(*message1);
+
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GeneratedMessageTest, NonEmptyMergeFrom) {
+ // Test merging with a non-empty message. Code is a modified form
+ // of that found in google/protobuf/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 i = message1.repeated_int32(0);
+ message1.clear_repeated_int32();
+ message1.add_repeated_int32(i);
+
+ message1.MergeFrom(message2);
+
+ TestUtil::ExpectAllFieldsSet(message1);
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST(GeneratedMessageTest, MergeFromSelf) {
+ unittest::TestAllTypes message;
+ EXPECT_DEATH(message.MergeFrom(message), "&from");
+ EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)),
+ "&from");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(GeneratedMessageTest, Serialization) {
+ unittest::TestAllTypes message1, message2;
+ string data;
+
+ TestUtil::SetAllFields(&message1);
+ message1.SerializeToString(&data);
+ EXPECT_TRUE(message2.ParseFromString(data));
+ TestUtil::ExpectAllFieldsSet(message2);
+
+}
+
+
+TEST(GeneratedMessageTest, 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(GeneratedMessageTest, 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(GeneratedMessageTest, 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(GeneratedMessageTest, ReallyLargeTagNumber) {
+ // Test that really large tag numbers don't break anything.
+ unittest::TestReallyLargeTagNumber message1, message2;
+ 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(GeneratedMessageTest, 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(GeneratedMessageTest, 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("qux");
+ 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("qux", message.repeatedstringfield(0));
+ EXPECT_EQ(unittest::FOREIGN_BAR, message.repeatedenumfield(0));
+ EXPECT_EQ(15, message.repeatedmessagefield(0).c());
+}
+
+TEST(GeneratedMessageTest, 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.ByteSize());
+
+ message.set_friend_(5);
+ EXPECT_EQ(5, message.friend_());
+}
+
+TEST(GeneratedMessageTest, 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.
+
+ protobuf_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(GeneratedMessageTest, TestEmbedOptimizedForSize) {
+ // Verifies that something optimized for speed can contain something optimized
+ // for size.
+
+ protobuf_unittest::TestEmbedOptimizedForSize message, message2;
+ message.mutable_optional_message()->set_i(1);
+ message.add_repeated_message()->mutable_msg()->set_c(2);
+ 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(GeneratedEnumTest, 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;
+ // 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(GeneratedEnumTest, 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(GeneratedEnumTest, MinAndMax) {
+ EXPECT_EQ(unittest::TestAllTypes::FOO,unittest::TestAllTypes::NestedEnum_MIN);
+ EXPECT_EQ(unittest::TestAllTypes::BAZ,unittest::TestAllTypes::NestedEnum_MAX);
+
+ EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN);
+ EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX);
+
+ EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN);
+ EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX);
+
+ EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN);
+ EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX);
+
+ // 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;
+ }
+}
+
+// ===================================================================
+
+// Support code for testing services.
+class GeneratedServiceTest : public testing::Test {
+ protected:
+ class MockTestService : public unittest::TestService {
+ public:
+ MockTestService()
+ : called_(false),
+ method_(""),
+ controller_(NULL),
+ request_(NULL),
+ response_(NULL),
+ done_(NULL) {}
+
+ ~MockTestService() {}
+
+ void Reset() { called_ = false; }
+
+ // implements TestService ----------------------------------------
+
+ void Foo(RpcController* controller,
+ const unittest::FooRequest* request,
+ unittest::FooResponse* response,
+ Closure* done) {
+ 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) {
+ ASSERT_FALSE(called_);
+ called_ = true;
+ method_ = "Bar";
+ controller_ = controller;
+ request_ = request;
+ response_ = response;
+ done_ = done;
+ }
+
+ // ---------------------------------------------------------------
+
+ bool called_;
+ string method_;
+ RpcController* controller_;
+ const Message* request_;
+ Message* response_;
+ Closure* done_;
+ };
+
+ class MockRpcChannel : public RpcChannel {
+ public:
+ MockRpcChannel()
+ : called_(false),
+ method_(NULL),
+ controller_(NULL),
+ request_(NULL),
+ response_(NULL),
+ done_(NULL),
+ destroyed_(NULL) {}
+
+ ~MockRpcChannel() {
+ if (destroyed_ != NULL) *destroyed_ = true;
+ }
+
+ void Reset() { called_ = false; }
+
+ // implements TestService ----------------------------------------
+
+ void CallMethod(const MethodDescriptor* method,
+ RpcController* controller,
+ const Message* request,
+ Message* response,
+ Closure* done) {
+ 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() {
+ ADD_FAILURE() << "Reset() not expected during this test.";
+ }
+ bool Failed() const {
+ ADD_FAILURE() << "Failed() not expected during this test.";
+ return false;
+ }
+ string ErrorText() const {
+ ADD_FAILURE() << "ErrorText() not expected during this test.";
+ return "";
+ }
+ void StartCancel() {
+ ADD_FAILURE() << "StartCancel() not expected during this test.";
+ }
+ void SetFailed(const string& reason) {
+ ADD_FAILURE() << "SetFailed() not expected during this test.";
+ }
+ bool IsCanceled() const {
+ ADD_FAILURE() << "IsCanceled() not expected during this test.";
+ return false;
+ }
+ void NotifyOnCancel(Closure* callback) {
+ ADD_FAILURE() << "NotifyOnCancel() not expected during this test.";
+ }
+ };
+
+ GeneratedServiceTest()
+ : descriptor_(unittest::TestService::descriptor()),
+ foo_(descriptor_->FindMethodByName("Foo")),
+ bar_(descriptor_->FindMethodByName("Bar")),
+ stub_(&mock_channel_),
+ done_(NewPermanentCallback(&DoNothing)) {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(foo_ != NULL);
+ ASSERT_TRUE(bar_ != NULL);
+ }
+
+ 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_;
+ scoped_ptr<Closure> done_;
+};
+
+TEST_F(GeneratedServiceTest, GetDescriptor) {
+ // Test that GetDescriptor() works.
+
+ EXPECT_EQ(descriptor_, mock_service_.GetDescriptor());
+}
+
+TEST_F(GeneratedServiceTest, GetChannel) {
+ EXPECT_EQ(&mock_channel_, stub_.channel());
+}
+
+TEST_F(GeneratedServiceTest, 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(GeneratedServiceTest, 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(GeneratedServiceTest, CallMethodTypeFailure) {
+ // Verify death if we call Foo() with Bar's message types.
+
+#ifdef GTEST_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 // GTEST_HAS_DEATH_TEST
+}
+
+TEST_F(GeneratedServiceTest, 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(GeneratedServiceTest, 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(GeneratedServiceTest, 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 string& reason) {
+ 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_);
+}
+
+} // namespace
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
new file mode 100644
index 00000000..61182933
--- /dev/null
+++ b/src/google/protobuf/compiler/importer.cc
@@ -0,0 +1,398 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <algorithm>
+
+#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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#ifdef _WIN32
+#ifndef F_OK
+#define F_OK 00 // not defined by MSVC for whatever reason
+#endif
+#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 string& filename,
+ MultiFileErrorCollector* multi_file_error_collector)
+ : filename_(filename),
+ multi_file_error_collector_(multi_file_error_collector),
+ had_errors_(false) {}
+ ~SingleFileErrorCollector() {}
+
+ bool had_errors() { return had_errors_; }
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(int line, int column, const string& message) {
+ if (multi_file_error_collector_ != NULL) {
+ multi_file_error_collector_->AddError(filename_, line, column, message);
+ }
+ had_errors_ = true;
+ }
+
+ private:
+ string filename_;
+ MultiFileErrorCollector* multi_file_error_collector_;
+ bool had_errors_;
+};
+
+// ===================================================================
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+ SourceTree* source_tree)
+ : source_tree_(source_tree),
+ error_collector_(NULL),
+ using_validation_error_collector_(false),
+ validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
+
+bool SourceTreeDescriptorDatabase::FindFileByName(
+ const string& filename, FileDescriptorProto* output) {
+ scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
+ if (input == NULL) {
+ if (error_collector_ != NULL) {
+ error_collector_->AddError(filename, -1, 0, "File not found.");
+ }
+ 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_ != NULL) {
+ 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 string& symbol_name, FileDescriptorProto* output) {
+ return false;
+}
+
+bool SourceTreeDescriptorDatabase::FindFileContainingExtension(
+ const 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 string& filename,
+ const string& element_name,
+ const Message* descriptor,
+ ErrorLocation location,
+ const string& message) {
+ if (owner_->error_collector_ == NULL) return;
+
+ int line, column;
+ owner_->source_locations_.Find(descriptor, location, &line, &column);
+ owner_->error_collector_->AddError(filename, line, column, message);
+}
+
+// ===================================================================
+
+Importer::Importer(SourceTree* source_tree,
+ MultiFileErrorCollector* error_collector)
+ : database_(source_tree),
+ pool_(&database_, database_.GetValidationErrorCollector()) {
+ database_.RecordErrorsTo(error_collector);
+}
+
+Importer::~Importer() {}
+
+const FileDescriptor* Importer::Import(const string& filename) {
+ return pool_.FindFileByName(filename);
+}
+
+// ===================================================================
+
+SourceTree::~SourceTree() {}
+
+DiskSourceTree::DiskSourceTree() {}
+
+DiskSourceTree::~DiskSourceTree() {}
+
+static inline char LastChar(const 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 string CanonicalizePath(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.
+ path = StringReplace(path, "\\", "/", true);
+#endif
+
+ vector<string> parts;
+ vector<string> canonical_parts;
+ SplitStringUsing(path, "/", &parts); // Note: Removes empty parts.
+ for (int i = 0; i < parts.size(); i++) {
+ if (parts[i] == ".") {
+ // Ignore.
+ } else {
+ canonical_parts.push_back(parts[i]);
+ }
+ }
+ string result = JoinStrings(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 string& path) {
+ return path == ".." ||
+ HasPrefixString(path, "../") ||
+ HasSuffixString(path, "/..") ||
+ path.find("/../") != 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 string& filename,
+ const string& old_prefix,
+ const string& new_prefix,
+ 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, "/")) {
+ // 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".
+ if (filename[old_prefix.size()] == '/') {
+ // Yep. So the prefixes are directories and the filename is a file
+ // inside them.
+ string after_prefix = filename.substr(old_prefix.size() + 1);
+ 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 string& virtual_path,
+ const string& disk_path) {
+ mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path)));
+}
+
+DiskSourceTree::DiskFileToVirtualFileResult
+DiskSourceTree::DiskFileToVirtualFile(
+ const string& disk_file,
+ string* virtual_file,
+ string* shadowing_disk_file) {
+ int mapping_index = -1;
+ 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.
+ scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
+ if (stream == NULL) {
+ return CANNOT_OPEN;
+ }
+
+ return SUCCESS;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
+ if (filename != CanonicalizePath(filename) ||
+ ContainsParentReference(filename)) {
+ // 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.
+ return NULL;
+ }
+
+ for (int i = 0; i < mappings_.size(); i++) {
+ string disk_file;
+ if (ApplyMapping(filename, mappings_[i].virtual_path,
+ mappings_[i].disk_path, &disk_file)) {
+ io::ZeroCopyInputStream* stream = OpenDiskFile(disk_file);
+ if (stream != NULL) return stream;
+
+ if (errno == EACCES) {
+ // The file exists but is not readable.
+ // TODO(kenton): Find a way to report this more nicely.
+ GOOGLE_LOG(WARNING) << "Read access is denied for file: " << disk_file;
+ return NULL;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
+ const string& filename) {
+ 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 NULL;
+ }
+}
+
+} // 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 00000000..2e3d0df4
--- /dev/null
+++ b/src/google/protobuf/compiler/importer.h
@@ -0,0 +1,279 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <vector>
+#include <set>
+#include <utility>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/compiler/parser.h>
+
+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 LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
+ public:
+ SourceTreeDescriptorDatabase(SourceTree* source_tree);
+ ~SourceTreeDescriptorDatabase();
+
+ // 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 string& filename, FileDescriptorProto* output);
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output);
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output);
+
+ private:
+ class SingleFileErrorCollector;
+
+ SourceTree* source_tree_;
+ MultiFileErrorCollector* error_collector_;
+
+ class LIBPROTOBUF_EXPORT ValidationErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ ValidationErrorCollector(SourceTreeDescriptorDatabase* owner);
+ ~ValidationErrorCollector();
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename,
+ const string& element_name,
+ const Message* descriptor,
+ ErrorLocation location,
+ const string& message);
+
+ 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 LIBPROTOBUF_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 string& filename);
+
+ // The DescriptorPool in which all imported FileDescriptors and their
+ // contents are stored.
+ inline const DescriptorPool* pool() const {
+ return &pool_;
+ }
+
+ 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 LIBPROTOBUF_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 string& filename, int line, int column,
+ const string& message) = 0;
+
+ 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 LIBPROTOBUF_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 string& filename) = 0;
+
+ 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 LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
+ public:
+ DiskSourceTree();
+ ~DiskSourceTree();
+
+ // 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 successfuly.
+ //
+ // 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 string& virtual_path, const 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 string& disk_file,
+ string* virtual_file,
+ string* shadowing_disk_file);
+
+ // implements SourceTree -------------------------------------------
+ io::ZeroCopyInputStream* Open(const string& filename);
+
+ private:
+ struct Mapping {
+ string virtual_path;
+ string disk_path;
+
+ inline Mapping(const string& virtual_path, const string& disk_path)
+ : virtual_path(virtual_path), disk_path(disk_path) {}
+ };
+ vector<Mapping> mappings_;
+
+ // Like Open() but given the actual on-disk path.
+ io::ZeroCopyInputStream* OpenDiskFile(const string& filename);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree);
+};
+
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..5b5d2831
--- /dev/null
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -0,0 +1,539 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/stubs/hash.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/common.h>
+#include <google/protobuf/testing/file.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 compiler {
+
+namespace {
+
+#define EXPECT_SUBSTRING(needle, haystack) \
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack))
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename, int line, int column,
+ const string& message) {
+ strings::SubstituteAndAppend(&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() {}
+
+ void AddFile(const string& name, const char* contents) {
+ files_[name] = contents;
+ }
+
+ // implements SourceTree -------------------------------------------
+ io::ZeroCopyInputStream* Open(const string& filename) {
+ const char* contents = FindPtrOrNull(files_, filename);
+ if (contents == NULL) {
+ return NULL;
+ } else {
+ return new io::ArrayInputStream(contents, strlen(contents));
+ }
+ }
+
+ private:
+ hash_map<string, const char*> files_;
+};
+
+// ===================================================================
+
+class ImporterTest : public testing::Test {
+ protected:
+ ImporterTest()
+ : importer_(&source_tree_, &error_collector_) {}
+
+ void AddFile(const string& filename, const char* text) {
+ source_tree_.AddFile(filename, text);
+ }
+
+ // Return the collected error text
+ string error() const { return error_collector_.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 != NULL);
+
+ 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 != NULL);
+ ASSERT_TRUE(bar != NULL);
+
+ // 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") == NULL);
+ 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") == NULL);
+ 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"
+ "import \"recursive2.proto\";\n");
+ AddFile("recursive2.proto",
+ "syntax = \"proto2\";\n"
+ "import \"recursive1.proto\";\n");
+
+ EXPECT_TRUE(importer_.Import("recursive1.proto") == NULL);
+ EXPECT_EQ(
+ "recursive1.proto:-1: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:-1:0: Import \"recursive2.proto\" was not found "
+ "or had errors.\n",
+ error_collector_.text_);
+}
+
+// TODO(sanjay): The MapField tests below more properly belong in
+// descriptor_unittest, but are more convenient to test here.
+TEST_F(ImporterTest, MapFieldValid) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Item {\n"
+ " required string key = 1;\n"
+ "}\n"
+ "message Map {\n"
+ " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ const FileDescriptor* file = importer_.Import("map.proto");
+ ASSERT_TRUE(file != NULL) << error_collector_.text_;
+ EXPECT_EQ("", error_collector_.text_);
+
+ // Check that Map::items points to Item::key
+ const Descriptor* item_type = file->FindMessageTypeByName("Item");
+ ASSERT_TRUE(item_type != NULL);
+ const Descriptor* map_type = file->FindMessageTypeByName("Map");
+ ASSERT_TRUE(map_type != NULL);
+ const FieldDescriptor* key_field = item_type->FindFieldByName("key");
+ ASSERT_TRUE(key_field != NULL);
+ const FieldDescriptor* items_field = map_type->FindFieldByName("items");
+ ASSERT_TRUE(items_field != NULL);
+ EXPECT_EQ(items_field->experimental_map_key(), key_field);
+}
+
+TEST_F(ImporterTest, MapFieldNotRepeated) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Item {\n"
+ " required string key = 1;\n"
+ "}\n"
+ "message Map {\n"
+ " required Item items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("only allowed for repeated fields", error());
+}
+
+TEST_F(ImporterTest, MapFieldNotMessageType) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Map {\n"
+ " repeated int32 items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("only allowed for fields with a message type", error());
+}
+
+TEST_F(ImporterTest, MapFieldTypeNotFound) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Map {\n"
+ " repeated Unknown items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("not defined", error());
+}
+
+TEST_F(ImporterTest, MapFieldKeyNotFound) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Item {\n"
+ " required string key = 1;\n"
+ "}\n"
+ "message Map {\n"
+ " repeated Item items = 1 [experimental_map_key = \"badkey\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("Could not find field", error());
+}
+
+TEST_F(ImporterTest, MapFieldKeyRepeated) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message Item {\n"
+ " repeated string key = 1;\n"
+ "}\n"
+ "message Map {\n"
+ " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("must not name a repeated field", error());
+}
+
+TEST_F(ImporterTest, MapFieldKeyNotScalar) {
+ AddFile(
+ "map.proto",
+ "syntax = \"proto2\";\n"
+ "message ItemKey { }\n"
+ "message Item {\n"
+ " required ItemKey key = 1;\n"
+ "}\n"
+ "message Map {\n"
+ " repeated Item items = 1 [experimental_map_key = \"key\"];\n"
+ "}\n"
+ );
+ EXPECT_TRUE(importer_.Import("map.proto") == NULL);
+ EXPECT_SUBSTRING("must name a scalar or string", error());
+}
+
+// ===================================================================
+
+class DiskSourceTreeTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ 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 (File::Exists(dirnames_[i])) {
+ File::DeleteRecursively(dirnames_[i], NULL, NULL);
+ }
+ GOOGLE_CHECK(File::CreateDir(dirnames_[i].c_str(), DEFAULT_FILE_MODE));
+ }
+ }
+
+ virtual void TearDown() {
+ for (int i = 0; i < dirnames_.size(); i++) {
+ File::DeleteRecursively(dirnames_[i], NULL, NULL);
+ }
+ }
+
+ void AddFile(const string& filename, const char* contents) {
+ File::WriteStringToFileOrDie(contents, filename);
+ }
+
+ void AddSubdir(const string& dirname) {
+ GOOGLE_CHECK(File::CreateDir(dirname.c_str(), DEFAULT_FILE_MODE));
+ }
+
+ void ExpectFileContents(const string& filename,
+ const char* expected_contents) {
+ scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+
+ ASSERT_FALSE(input == NULL);
+
+ // Read all the data from the file.
+ 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 ExpectFileNotFound(const string& filename) {
+ scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+ EXPECT_TRUE(input == NULL);
+ }
+
+ DiskSourceTree source_tree_;
+
+ // Paths of two on-disk directories to use during the test.
+ vector<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!");
+ ExpectFileNotFound("bar");
+}
+
+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!");
+ ExpectFileNotFound("baz/bar");
+ ExpectFileNotFound("foo");
+ ExpectFileNotFound("bar");
+
+ // Non-canonical file names should not work.
+ ExpectFileNotFound("baz//foo");
+ ExpectFileNotFound("baz/../baz/foo");
+ ExpectFileNotFound("baz/./foo");
+ ExpectFileNotFound("baz/foo/");
+}
+
+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.");
+ ExpectFileNotFound("../foo");
+ ExpectFileNotFound("../bar/baz");
+}
+
+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!");
+ ExpectFileNotFound("bar");
+}
+
+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!");
+ ExpectFileNotFound("baz");
+}
+
+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.
+ ASSERT_TRUE(File::CreateDir((dirnames_[0] + "/bar").c_str(),
+ DEFAULT_FILE_MODE));
+
+ // 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]);
+
+ string virtual_file;
+ 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");
+
+ string virtual_file;
+ 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));
+
+ // 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);
+}
+
+} // namespace
+
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
new file mode 100644
index 00000000..aa15a468
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -0,0 +1,189 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ for (int i = 0; i < descriptor_->value_count(); i++) {
+ const EnumValueDescriptor* value = descriptor_->value(i);
+ const EnumValueDescriptor* canonical_value =
+ descriptor_->FindValueByNumber(value->number());
+
+ if (value == canonical_value) {
+ 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) {
+ bool is_own_file =
+ descriptor_->containing_type() == NULL &&
+ descriptor_->file()->options().java_multiple_files();
+ printer->Print(
+ "public $static$ enum $classname$ {\n",
+ "static", is_own_file ? "" : "static",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ map<string, string> vars;
+ vars["name"] = canonical_values_[i]->name();
+ vars["index"] = SimpleItoa(canonical_values_[i]->index());
+ vars["number"] = SimpleItoa(canonical_values_[i]->number());
+ printer->Print(vars,
+ "$name$($index$, $number$),\n");
+ }
+
+ printer->Print(
+ ";\n"
+ "\n");
+
+ // -----------------------------------------------------------------
+
+ for (int i = 0; i < aliases_.size(); i++) {
+ map<string, string> vars;
+ vars["classname"] = descriptor_->name();
+ vars["name"] = aliases_[i].value->name();
+ vars["canonical_name"] = aliases_[i].canonical_value->name();
+ printer->Print(vars,
+ "public static final $classname$ $name$ = $canonical_name$;\n");
+ }
+
+ // -----------------------------------------------------------------
+
+ printer->Print(
+ "\n"
+ "public final int getNumber() { return value; }\n"
+ "\n"
+ "public static $classname$ valueOf(int value) {\n"
+ " switch (value) {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Indent();
+
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ printer->Print(
+ "case $number$: return $name$;\n",
+ "name", canonical_values_[i]->name(),
+ "number", SimpleItoa(canonical_values_[i]->number()));
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " default: return null;\n"
+ " }\n"
+ "}\n"
+ "\n");
+
+ // -----------------------------------------------------------------
+ // Reflection
+
+ printer->Print(
+ "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
+ " getValueDescriptor() {\n"
+ " return getDescriptor().getValues().get(index);\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");
+
+ // 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) {
+ printer->Print(
+ " return $file$.getDescriptor().getEnumTypes().get($index$);\n",
+ "file", ClassName(descriptor_->file()),
+ "index", SimpleItoa(descriptor_->index()));
+ } else {
+ printer->Print(
+ " return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
+ "parent", ClassName(descriptor_->containing_type()),
+ "index", SimpleItoa(descriptor_->index()));
+ }
+
+ printer->Print(
+ "}\n"
+ "\n"
+ "private static final $classname$[] VALUES = {\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"
+ "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"
+ " return VALUES[desc.getIndex()];\n"
+ "}\n",
+ "classname", descriptor_->name());
+
+ // -----------------------------------------------------------------
+
+ printer->Print(
+ "private final int index;\n"
+ "private final int value;\n"
+ "private $classname$(int index, int value) {\n"
+ " this.index = index;\n"
+ " this.value = value;\n"
+ "}\n",
+ "classname", descriptor_->name());
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h
new file mode 100644
index 00000000..f0a16036
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class EnumGenerator {
+ public:
+ explicit EnumGenerator(const EnumDescriptor* descriptor);
+ ~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.
+ vector<const EnumValueDescriptor*> canonical_values_;
+
+ struct Alias {
+ const EnumValueDescriptor* value;
+ const EnumValueDescriptor* canonical_value;
+ };
+ vector<Alias> aliases_;
+
+ 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/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
new file mode 100644
index 00000000..cb80c4b8
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -0,0 +1,264 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetEnumVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ const EnumValueDescriptor* default_value;
+ default_value = descriptor->default_value_enum();
+
+ string type = ClassName(descriptor->enum_type());
+
+ (*variables)["name"] =
+ UnderscoresToCamelCase(descriptor);
+ (*variables)["capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(descriptor);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["type"] = type;
+ (*variables)["default"] = type + "." + default_value->name();
+}
+
+} // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::
+EnumFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private boolean has$capitalized_name$;\n"
+ "private $type$ $name$_ = $default$;\n"
+ "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+ "public $type$ get$capitalized_name$() { return $name$_; }\n");
+}
+
+void EnumFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return result.has$capitalized_name$();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " return result.get$capitalized_name$();\n"
+ "}\n"
+ "public Builder set$capitalized_name$($type$ value) {\n"
+ " result.has$capitalized_name$ = true;\n"
+ " result.$name$_ = value;\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.has$capitalized_name$ = false;\n"
+ " result.$name$_ = $default$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // Nothing to do here for enum types.
+}
+
+void EnumFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n"
+ " unknownFields.mergeVarintField($number$, rawValue);\n"
+ "} else {\n"
+ " set$capitalized_name$(value);\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " output.writeEnum($number$, get$capitalized_name$().getNumber());\n"
+ "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSize($number$, get$capitalized_name$().getNumber());\n"
+ "}\n");
+}
+
+string EnumFieldGenerator::GetBoxedType() const {
+ return ClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetEnumVariables(descriptor, &variables_);
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private java.util.List<$type$> $name$_ =\n"
+ " java.util.Collections.emptyList();\n"
+ "public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return $name$_;\n" // note: unmodifiable list
+ "}\n"
+ "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ 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.
+ "public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return result.get$capitalized_name$Count();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return result.get$capitalized_name$(index);\n"
+ "}\n"
+ "public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ " result.$name$_.set(index, value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder add$capitalized_name$($type$ value) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " result.$name$_.add(value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " super.addAll(values, result.$name$_);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.$name$_ = java.util.Collections.emptyList();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " result.$name$_.addAll(other.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
+ " result.$name$_ =\n"
+ " java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int rawValue = input.readEnum();\n"
+ "$type$ value = $type$.valueOf(rawValue);\n"
+ "if (value == null) {\n"
+ " unknownFields.mergeVarintField($number$, rawValue);\n"
+ "} else {\n"
+ " add$capitalized_name$(value);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.writeEnum($number$, element.getNumber());\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSize($number$, element.getNumber());\n"
+ "}\n");
+}
+
+string RepeatedEnumFieldGenerator::GetBoxedType() const {
+ return ClassName(descriptor_->enum_type());
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
new file mode 100644
index 00000000..473ba617
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class EnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+ ~EnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
new file mode 100644
index 00000000..1b637fab
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::Generate(io::Printer* printer) {
+ map<string, string> vars;
+ vars["name"] = UnderscoresToCamelCase(descriptor_);
+ vars["containing_type"] = ClassName(descriptor_->containing_type());
+ vars["index"] = SimpleItoa(descriptor_->index());
+
+ JavaType java_type = GetJavaType(descriptor_);
+ string singular_type;
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ vars["type"] = ClassName(descriptor_->message_type());
+ break;
+ case JAVATYPE_ENUM:
+ vars["type"] = ClassName(descriptor_->enum_type());
+ break;
+ default:
+ vars["type"] = BoxedPrimitiveTypeName(java_type);
+ break;
+ }
+
+ if (descriptor_->is_repeated()) {
+ printer->Print(vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " java.util.List<$type$>> $name$ =\n"
+ " com.google.protobuf.GeneratedMessage\n"
+ " .newRepeatedGeneratedExtension(\n"
+ " getDescriptor().getExtensions().get($index$),\n"
+ " $type$.class);\n");
+ } else {
+ printer->Print(vars,
+ "public static final\n"
+ " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+ " $containing_type$,\n"
+ " $type$> $name$ =\n"
+ " com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n"
+ " getDescriptor().getExtensions().get($index$),\n"
+ " $type$.class);\n");
+ }
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
new file mode 100644
index 00000000..9088fecd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FieldDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+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(const FieldDescriptor* descriptor);
+ ~ExtensionGenerator();
+
+ void Generate(io::Printer* printer);
+
+ private:
+ const FieldDescriptor* descriptor_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
new file mode 100644
index 00000000..b7197cac
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -0,0 +1,88 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+FieldGenerator::~FieldGenerator() {}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+ : descriptor_(descriptor),
+ field_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
+ extension_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+
+ // Construct all the FieldGenerators.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
+ }
+ for (int i = 0; i < descriptor->extension_count(); i++) {
+ extension_generators_[i].reset(MakeGenerator(descriptor->extension(i)));
+ }
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
+ if (field->is_repeated()) {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ return new RepeatedMessageFieldGenerator(field);
+ case JAVATYPE_ENUM:
+ return new RepeatedEnumFieldGenerator(field);
+ default:
+ return new RepeatedPrimitiveFieldGenerator(field);
+ }
+ } else {
+ switch (GetJavaType(field)) {
+ case JAVATYPE_MESSAGE:
+ return new MessageFieldGenerator(field);
+ case JAVATYPE_ENUM:
+ return new EnumFieldGenerator(field);
+ default:
+ return new PrimitiveFieldGenerator(field);
+ }
+ }
+}
+
+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];
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
new file mode 100644
index 00000000..ef47c735
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class FieldGenerator {
+ public:
+ FieldGenerator() {}
+ virtual ~FieldGenerator();
+
+ virtual void GenerateMembers(io::Printer* printer) const = 0;
+ virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
+ virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+ virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
+ virtual void GenerateParsingCode(io::Printer* printer) const = 0;
+ virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+ virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+
+ virtual string GetBoxedType() const = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+ explicit FieldGeneratorMap(const Descriptor* descriptor);
+ ~FieldGeneratorMap();
+
+ const FieldGenerator& get(const FieldDescriptor* field) const;
+ const FieldGenerator& get_extension(int index) const;
+
+ private:
+ const Descriptor* descriptor_;
+ scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
+
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
new file mode 100644
index 00000000..e7e8618d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -0,0 +1,249 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_file.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_service.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message.h>
+#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.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+FileGenerator::FileGenerator(const FileDescriptor* file)
+ : file_(file),
+ java_package_(FileJavaPackage(file)),
+ classname_(FileClassName(file)) {}
+
+FileGenerator::~FileGenerator() {}
+
+bool FileGenerator::Validate(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.
+
+ bool found_conflict = false;
+ for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
+ if (file_->enum_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
+ if (file_->message_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
+ if (file_->service(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+
+ if (found_conflict) {
+ 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;
+ }
+
+ 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"
+ "\n");
+ if (!java_package_.empty()) {
+ printer->Print(
+ "package $package$;\n"
+ "\n",
+ "package", java_package_);
+ }
+ printer->Print(
+ "public final class $classname$ {\n"
+ " private $classname$() {}\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // -----------------------------------------------------------------
+
+ // 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);
+ string file_data;
+ file_proto.SerializeToString(&file_data);
+
+ 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 = buildDescriptor();\n"
+ "private static\n"
+ " com.google.protobuf.Descriptors.FileDescriptor\n"
+ " buildDescriptor() {\n"
+ " java.lang.String descriptorData =\n");
+ printer->Indent();
+ printer->Indent();
+
+ // Only write 40 bytes per line.
+ static const int kBytesPerLine = 40;
+ for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+ if (i > 0) printer->Print(" +\n");
+ printer->Print("\"$data$\"",
+ "data", CEscape(file_data.substr(i, kBytesPerLine)));
+ }
+ printer->Print(";\n");
+
+ printer->Outdent();
+ printer->Print(
+ "try {\n"
+ " return com.google.protobuf.Descriptors.FileDescriptor\n"
+ " .internalBuildGeneratedFileFrom(descriptorData,\n"
+ " new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
+
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ printer->Print(
+ " $dependency$.getDescriptor(),\n",
+ "dependency", ClassName(file_->dependency(i)));
+ }
+
+ printer->Print(
+ " });\n"
+ "} catch (Exception e) {\n"
+ " throw new RuntimeException(\n"
+ " \"Failed to parse protocol buffer descriptor for \" +\n"
+ " \"\\\"$filename$\\\".\", e);\n"
+ "}\n",
+ "filename", file_->name());
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+
+ // -----------------------------------------------------------------
+
+ if (!file_->options().java_multiple_files()) {
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator(file_->enum_type(i)).Generate(printer);
+ }
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ MessageGenerator(file_->message_type(i)).Generate(printer);
+ }
+ for (int i = 0; i < file_->service_count(); i++) {
+ ServiceGenerator(file_->service(i)).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++) {
+ ExtensionGenerator(file_->extension(i)).Generate(printer);
+ }
+
+ // Static variables.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+template<typename GeneratorClass, typename DescriptorClass>
+static void GenerateSibling(const string& package_dir,
+ const string& java_package,
+ const DescriptorClass* descriptor,
+ OutputDirectory* output_directory,
+ vector<string>* file_list) {
+ string filename = package_dir + descriptor->name() + ".java";
+ file_list->push_back(filename);
+
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filename));
+ io::Printer printer(output.get(), '$');
+
+ printer.Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "\n");
+ if (!java_package.empty()) {
+ printer.Print(
+ "package $package$;\n"
+ "\n",
+ "package", java_package);
+ }
+
+ GeneratorClass(descriptor).Generate(&printer);
+}
+
+void FileGenerator::GenerateSiblings(const string& package_dir,
+ OutputDirectory* output_directory,
+ vector<string>* file_list) {
+ if (file_->options().java_multiple_files()) {
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ GenerateSibling<EnumGenerator>(package_dir, java_package_,
+ file_->enum_type(i),
+ output_directory, file_list);
+ }
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ GenerateSibling<MessageGenerator>(package_dir, java_package_,
+ file_->message_type(i),
+ output_directory, file_list);
+ }
+ for (int i = 0; i < file_->service_count(); i++) {
+ GenerateSibling<ServiceGenerator>(package_dir, java_package_,
+ file_->service(i),
+ output_directory, file_list);
+ }
+ }
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
new file mode 100644
index 00000000..9eeec253
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+ namespace compiler {
+ class OutputDirectory; // code_generator.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class FileGenerator {
+ public:
+ explicit FileGenerator(const FileDescriptor* file);
+ ~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(string* error);
+
+ void Generate(io::Printer* printer);
+
+ // 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 string& package_dir,
+ OutputDirectory* output_directory,
+ vector<string>* file_list);
+
+ const string& java_package() { return java_package_; }
+ const string& classname() { return classname_; }
+
+ private:
+ const FileDescriptor* file_;
+ string java_package_;
+ string classname_;
+
+ 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/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
new file mode 100644
index 00000000..89a32da4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -0,0 +1,133 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_generator.h>
+#include <google/protobuf/compiler/java/java_file.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+// Parses a set of comma-delimited name/value pairs, e.g.:
+// "foo=bar,baz,qux=corge"
+// parses to the pairs:
+// ("foo", "bar"), ("baz", ""), ("qux", "corge")
+void ParseOptions(const string& text, vector<pair<string, string> >* output) {
+ vector<string> parts;
+ SplitStringUsing(text, ",", &parts);
+
+ for (int i = 0; i < parts.size(); i++) {
+ string::size_type equals_pos = parts[i].find_first_of('=');
+ pair<string, string> value;
+ if (equals_pos == 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);
+ }
+}
+
+} // namespace
+
+JavaGenerator::JavaGenerator() {}
+JavaGenerator::~JavaGenerator() {}
+
+bool JavaGenerator::Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const {
+ vector<pair<string, string> > options;
+ ParseOptions(parameter, &options);
+
+ // -----------------------------------------------------------------
+ // parse generator options
+
+ // Name a file where we will write a list of generated file names, one
+ // per line.
+ string output_list_file;
+
+ for (int i = 0; i < options.size(); i++) {
+ if (options[i].first == "output_list_file") {
+ output_list_file = options[i].second;
+ } else {
+ *error = "Unknown generator option: " + options[i].first;
+ return false;
+ }
+ }
+
+
+ // -----------------------------------------------------------------
+
+
+ FileGenerator file_generator(file);
+ if (!file_generator.Validate(error)) {
+ return false;
+ }
+
+ string package_dir =
+ StringReplace(file_generator.java_package(), ".", "/", true);
+ if (!package_dir.empty()) package_dir += "/";
+
+ vector<string> all_files;
+
+ string java_filename = package_dir;
+ java_filename += file_generator.classname();
+ java_filename += ".java";
+ all_files.push_back(java_filename);
+
+ // Generate main java file.
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(java_filename));
+ io::Printer printer(output.get(), '$');
+ file_generator.Generate(&printer);
+
+ // Generate sibling files.
+ file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
+
+ // Generate output list if requested.
+ if (!output_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .java files being generated.
+ scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+ output_directory->Open(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]);
+ }
+ }
+
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
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 00000000..11886aa0
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_generator.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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>
+
+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 LIBPROTOC_EXPORT JavaGenerator : public CodeGenerator {
+ public:
+ JavaGenerator();
+ ~JavaGenerator();
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
new file mode 100644
index 00000000..4ba82c2a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -0,0 +1,229 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+const char kThickSeparator[] =
+ "// ===================================================================\n";
+const char kThinSeparator[] =
+ "// -------------------------------------------------------------------\n";
+
+namespace {
+
+const char* kDefaultPackage = "";
+
+const string& FieldName(const FieldDescriptor* field) {
+ // 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 (field->type() == FieldDescriptor::TYPE_GROUP) {
+ return field->message_type()->name();
+ } else {
+ return field->name();
+ }
+}
+
+string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
+ 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;
+ }
+ }
+ return result;
+}
+
+} // namespace
+
+string UnderscoresToCamelCase(const FieldDescriptor* field) {
+ return UnderscoresToCamelCaseImpl(FieldName(field), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
+ return UnderscoresToCamelCaseImpl(FieldName(field), true);
+}
+
+string UnderscoresToCamelCase(const MethodDescriptor* method) {
+ return UnderscoresToCamelCaseImpl(method->name(), false);
+}
+
+string StripProto(const string& filename) {
+ if (HasSuffixString(filename, ".protodevel")) {
+ return StripSuffixString(filename, ".protodevel");
+ } else {
+ return StripSuffixString(filename, ".proto");
+ }
+}
+
+string FileClassName(const FileDescriptor* file) {
+ if (file->options().has_java_outer_classname()) {
+ return file->options().java_outer_classname();
+ } else {
+ string basename;
+ string::size_type last_slash = file->name().find_last_of('/');
+ if (last_slash == string::npos) {
+ basename = file->name();
+ } else {
+ basename = file->name().substr(last_slash + 1);
+ }
+ return UnderscoresToCamelCaseImpl(StripProto(basename), true);
+ }
+}
+
+string FileJavaPackage(const FileDescriptor* file) {
+ if (file->options().has_java_package()) {
+ return file->options().java_package();
+ } else {
+ string result = kDefaultPackage;
+ if (!file->package().empty()) {
+ if (!result.empty()) result += '.';
+ result += file->package();
+ }
+ return result;
+ }
+}
+
+string ToJavaName(const string& full_name, const FileDescriptor* file) {
+ string result;
+ if (file->options().java_multiple_files()) {
+ result = FileJavaPackage(file);
+ } else {
+ result = ClassName(file);
+ }
+ if (!result.empty()) {
+ result += '.';
+ }
+ if (file->package().empty()) {
+ result += full_name;
+ } else {
+ // Strip the proto package from full_name since we've replaced it with
+ // the Java package.
+ result += full_name.substr(file->package().size() + 1);
+ }
+ return result;
+}
+
+string ClassName(const FileDescriptor* descriptor) {
+ string result = FileJavaPackage(descriptor);
+ if (!result.empty()) result += '.';
+ result += FileClassName(descriptor);
+ return result;
+}
+
+JavaType GetJavaType(FieldDescriptor::Type field_type) {
+ switch (field_type) {
+ 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* 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;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
new file mode 100644
index 00000000..74376330
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -0,0 +1,102 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/descriptor.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[];
+
+// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
+// "fooBarBaz" or "FooBarBaz", respectively.
+string UnderscoresToCamelCase(const FieldDescriptor* field);
+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.)
+string UnderscoresToCamelCase(const MethodDescriptor* method);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Gets the unqualified class name for the file. Each .proto file becomes a
+// single Java class, with all its contents nested in that class.
+string FileClassName(const FileDescriptor* file);
+
+// Returns the file's Java package name.
+string FileJavaPackage(const FileDescriptor* file);
+
+// Converts the given fully-qualified name in the proto namespace to its
+// fully-qualified name in the Java namespace, given that it is in the given
+// file.
+string ToJavaName(const string& full_name, const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+inline string ClassName(const Descriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+inline string ClassName(const EnumDescriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+inline string ClassName(const ServiceDescriptor* descriptor) {
+ return ToJavaName(descriptor->full_name(), descriptor->file());
+}
+string ClassName(const FileDescriptor* descriptor);
+
+enum JavaType {
+ JAVATYPE_INT,
+ JAVATYPE_LONG,
+ JAVATYPE_FLOAT,
+ JAVATYPE_DOUBLE,
+ JAVATYPE_BOOLEAN,
+ JAVATYPE_STRING,
+ JAVATYPE_BYTES,
+ JAVATYPE_ENUM,
+ JAVATYPE_MESSAGE
+};
+
+JavaType GetJavaType(FieldDescriptor::Type field_type);
+
+inline JavaType GetJavaType(const FieldDescriptor* field) {
+ return GetJavaType(field->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);
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
new file mode 100644
index 00000000..ebba1f7b
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -0,0 +1,722 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+
+namespace {
+
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+ // Print the field's proto-syntax definition as a comment. We don't want to
+ // print group bodies so we cut off after the first line.
+ string def = field->DebugString();
+ printer->Print("// $def$\n",
+ "def", def.substr(0, def.find_first_of('\n')));
+}
+
+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.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+ const FieldDescriptor** fields =
+ new const FieldDescriptor*[descriptor->field_count()];
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ fields[i] = descriptor->field(i);
+ }
+ sort(fields, fields + descriptor->field_count(),
+ FieldOrderingByNumber());
+ return fields;
+}
+
+// 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.
+string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
+ return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
+}
+
+// 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).
+static bool HasRequiredFields(
+ const Descriptor* type,
+ hash_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 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (HasRequiredFields(field->message_type(), already_seen)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool HasRequiredFields(const Descriptor* type) {
+ hash_set<const Descriptor*> already_seen;
+ return HasRequiredFields(type, &already_seen);
+}
+
+} // namespace
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor)
+ : descriptor_(descriptor),
+ field_generators_(descriptor) {
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+ // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+ // used in the construction of descriptors, we have a tricky bootstrapping
+ // problem. To help control static initialization order, we make sure all
+ // descriptors and other static data that depends on them are members of
+ // the outermost class in the file. This way, they will be initialized in
+ // a deterministic order.
+
+ map<string, string> vars;
+ vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+ vars["index"] = SimpleItoa(descriptor_->index());
+ vars["classname"] = ClassName(descriptor_);
+ if (descriptor_->containing_type() != NULL) {
+ vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
+ }
+ if (descriptor_->file()->options().java_multiple_files()) {
+ // We can only make these package-private since the classes that use them
+ // are in separate files.
+ vars["private"] = "";
+ } else {
+ vars["private"] = "private ";
+ }
+
+ // The descriptor for this type.
+ if (descriptor_->containing_type() == NULL) {
+ printer->Print(vars,
+ "$private$static final com.google.protobuf.Descriptors.Descriptor\n"
+ " internal_$identifier$_descriptor =\n"
+ " getDescriptor().getMessageTypes().get($index$);\n");
+ } else {
+ printer->Print(vars,
+ "$private$static final com.google.protobuf.Descriptors.Descriptor\n"
+ " internal_$identifier$_descriptor =\n"
+ " internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
+ }
+
+ // And the FieldAccessorTable.
+ printer->Print(vars,
+ "$private$static\n"
+ " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+ " internal_$identifier$_fieldAccessorTable = new\n"
+ " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
+ " internal_$identifier$_descriptor,\n"
+ " new java.lang.String[] { ");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print(
+ "\"$field_name$\", ",
+ "field_name",
+ UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
+ }
+ printer->Print("},\n"
+ " $classname$.class,\n"
+ " $classname$.Builder.class);\n",
+ "classname", ClassName(descriptor_));
+
+ // Generate static members for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // TODO(kenton): Reuse MessageGenerator objects?
+ MessageGenerator(descriptor_->nested_type(i))
+ .GenerateStaticVariables(printer);
+ }
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+ bool is_own_file =
+ descriptor_->containing_type() == NULL &&
+ descriptor_->file()->options().java_multiple_files();
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "public $static$ final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+ " $classname$> {\n",
+ "static", is_own_file ? "" : "static",
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "public $static$ final class $classname$ extends\n"
+ " com.google.protobuf.GeneratedMessage {\n",
+ "static", is_own_file ? "" : "static",
+ "classname", descriptor_->name());
+ }
+ printer->Indent();
+ printer->Print(
+ "// Use $classname$.newBuilder() to construct.\n"
+ "private $classname$() {}\n"
+ "\n"
+ "private static final $classname$ defaultInstance = new $classname$();\n"
+ "public static $classname$ getDefaultInstance() {\n"
+ " return defaultInstance;\n"
+ "}\n"
+ "\n"
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return defaultInstance;\n"
+ "}\n"
+ "\n",
+ "classname", descriptor_->name());
+ printer->Print(
+ "public static final com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptor() {\n"
+ " return $fileclass$.internal_$identifier$_descriptor;\n"
+ "}\n"
+ "\n"
+ "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+ " internalGetFieldAccessorTable() {\n"
+ " return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
+ "}\n"
+ "\n",
+ "fileclass", ClassName(descriptor_->file()),
+ "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+ // Nested types and extensions
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator(descriptor_->enum_type(i)).Generate(printer);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator(descriptor_->nested_type(i)).Generate(printer);
+ }
+
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator(descriptor_->extension(i)).Generate(printer);
+ }
+
+ // Fields
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ PrintFieldComment(printer, descriptor_->field(i));
+ field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+ printer->Print("\n");
+ }
+
+ if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ GenerateIsInitialized(printer);
+ GenerateMessageSerializationMethods(printer);
+ }
+
+ GenerateParseFromMethods(printer);
+ GenerateBuilder(printer);
+}
+
+// ===================================================================
+
+void MessageGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+ sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeOrdering());
+
+ printer->Print(
+ "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
+ " throws java.io.IOException {\n");
+ printer->Indent();
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "com.google.protobuf.GeneratedMessage.ExtendableMessage\n"
+ " .ExtensionWriter extensionWriter = newExtensionWriter();\n");
+ }
+
+ // 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"
+ "private int memoizedSerializedSize = -1;\n"
+ "public int getSerializedSize() {\n"
+ " int size = memoizedSerializedSize;\n"
+ " if (size != -1) return size;\n"
+ "\n"
+ " size = 0;\n");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ 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->Outdent();
+ printer->Print(
+ " memoizedSerializedSize = size;\n"
+ " return size;\n"
+ "}\n"
+ "\n");
+}
+
+void MessageGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+ printer->Print(
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.ByteString data)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
+ " return newBuilder().mergeFrom(data).buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.ByteString data,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
+ " return newBuilder().mergeFrom(data, extensionRegistry)\n"
+ " .buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(byte[] data)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
+ " return newBuilder().mergeFrom(data).buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " byte[] data,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
+ " return newBuilder().mergeFrom(data, extensionRegistry)\n"
+ " .buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(java.io.InputStream input)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeFrom(input).buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " java.io.InputStream input,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeFrom(input, extensionRegistry)\n"
+ " .buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.CodedInputStream input)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeFrom(input).buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeFrom(input, extensionRegistry)\n"
+ " .buildParsed();\n"
+ "}\n"
+ "\n",
+ "classname", ClassName(descriptor_));
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+ io::Printer* printer, const FieldDescriptor* field) {
+ field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void MessageGenerator::GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range) {
+ printer->Print(
+ "extensionWriter.writeUntil($end$, output);\n",
+ "end", SimpleItoa(range->end));
+}
+
+// ===================================================================
+
+void MessageGenerator::GenerateBuilder(io::Printer* printer) {
+ printer->Print(
+ "public static Builder newBuilder() { return new Builder(); }\n"
+ "public Builder newBuilderForType() { return new Builder(); }\n"
+ "public static Builder newBuilder($classname$ prototype) {\n"
+ " return new Builder().mergeFrom(prototype);\n"
+ "}\n"
+ "\n",
+ "classname", ClassName(descriptor_));
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "public static final class Builder extends\n"
+ " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+ " $classname$, Builder> {\n",
+ "classname", ClassName(descriptor_));
+ } else {
+ printer->Print(
+ "public static final class Builder extends\n"
+ " com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
+ "classname", ClassName(descriptor_));
+ }
+ printer->Indent();
+
+ GenerateCommonBuilderMethods(printer);
+
+ if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ GenerateBuilderParsingMethods(printer);
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_->field(i));
+ field_generators_.get(descriptor_->field(i))
+ .GenerateBuilderMembers(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
+ printer->Print(
+ "// Construct using $classname$.newBuilder()\n"
+ "private Builder() {}\n"
+ "\n"
+ "$classname$ result = new $classname$();\n"
+ "\n"
+ "protected $classname$ internalGetResult() {\n"
+ " return result;\n"
+ "}\n"
+ "\n"
+ "public Builder clear() {\n"
+ " result = new $classname$();\n"
+ " return this;\n"
+ "}\n"
+ "\n"
+ "public Builder clone() {\n"
+ " return new Builder().mergeFrom(result);\n"
+ "}\n"
+ "\n"
+ "public com.google.protobuf.Descriptors.Descriptor\n"
+ " getDescriptorForType() {\n"
+ " return $classname$.getDescriptor();\n"
+ "}\n"
+ "\n"
+ "public $classname$ getDefaultInstanceForType() {\n"
+ " return $classname$.getDefaultInstance();\n"
+ "}\n"
+ "\n",
+ "classname", ClassName(descriptor_));
+
+ // -----------------------------------------------------------------
+
+ printer->Print(
+ "public $classname$ build() {\n"
+ " if (!isInitialized()) {\n"
+ " throw new com.google.protobuf.UninitializedMessageException(\n"
+ " result);\n"
+ " }\n"
+ " return buildPartial();\n"
+ "}\n"
+ "\n"
+ "private $classname$ buildParsed()\n"
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
+ " if (!isInitialized()) {\n"
+ " throw new com.google.protobuf.UninitializedMessageException(\n"
+ " result).asInvalidProtocolBufferException();\n"
+ " }\n"
+ " return buildPartial();\n"
+ "}\n"
+ "\n"
+ "public $classname$ buildPartial() {\n",
+ "classname", ClassName(descriptor_));
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " $classname$ returnMe = result;\n"
+ " result = null;\n"
+ " return returnMe;\n"
+ "}\n"
+ "\n",
+ "classname", ClassName(descriptor_));
+
+ // -----------------------------------------------------------------
+
+ if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(
+ "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
+ " if (other instanceof $classname$) {\n"
+ " return mergeFrom(($classname$)other);\n"
+ " } else {\n"
+ " super.mergeFrom(other);\n"
+ " return this;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "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", ClassName(descriptor_));
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i)).GenerateMergingCode(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " this.mergeUnknownFields(other.getUnknownFields());\n"
+ " return this;\n"
+ "}\n"
+ "\n");
+ }
+}
+
+// ===================================================================
+
+void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "public Builder mergeFrom(\n"
+ " com.google.protobuf.CodedInputStream input)\n"
+ " throws java.io.IOException {\n"
+ " return mergeFrom(input,\n"
+ " com.google.protobuf.ExtensionRegistry.getEmptyRegistry());\n"
+ "}\n"
+ "\n"
+ "public Builder mergeFrom(\n"
+ " com.google.protobuf.CodedInputStream input,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws java.io.IOException {\n");
+ printer->Indent();
+
+ printer->Print(
+ "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+ " com.google.protobuf.UnknownFieldSet.newBuilder(\n"
+ " this.getUnknownFields());\n"
+ "while (true) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "int tag = input.readTag();\n"
+ "switch (tag) {\n");
+ printer->Indent();
+
+ printer->Print(
+ "case 0:\n" // zero signals EOF / limit reached
+ " this.setUnknownFields(unknownFields.build());\n"
+ " return this;\n"
+ "default: {\n"
+ " if (!parseUnknownField(input, unknownFields,\n"
+ " extensionRegistry, tag)) {\n"
+ " this.setUnknownFields(unknownFields.build());\n"
+ " return this;\n" // it's an endgroup tag
+ " }\n"
+ " break;\n"
+ "}\n");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ uint32 tag = WireFormat::MakeTag(field->number(),
+ WireFormat::WireTypeForFieldType(field->type()));
+
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateParsingCode(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // switch (tag)
+ " }\n" // while (true)
+ "}\n"
+ "\n");
+}
+
+// ===================================================================
+
+void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+ printer->Print(
+ "public final boolean isInitialized() {\n");
+ printer->Indent();
+
+ // Check that all required fields in this message are set.
+ // TODO(kenton): We can optimize this when we switch to putting all the
+ // "has" fields into a single bitfield.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (field->is_required()) {
+ printer->Print(
+ "if (!has$name$) return false;\n",
+ "name", UnderscoresToCapitalizedCamelCase(field));
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ HasRequiredFields(field->message_type())) {
+ switch (field->label()) {
+ case FieldDescriptor::LABEL_REQUIRED:
+ printer->Print(
+ "if (!get$name$().isInitialized()) return false;\n",
+ "type", ClassName(field->message_type()),
+ "name", UnderscoresToCapitalizedCamelCase(field));
+ break;
+ case FieldDescriptor::LABEL_OPTIONAL:
+ printer->Print(
+ "if (has$name$()) {\n"
+ " if (!get$name$().isInitialized()) return false;\n"
+ "}\n",
+ "type", ClassName(field->message_type()),
+ "name", UnderscoresToCapitalizedCamelCase(field));
+ break;
+ case FieldDescriptor::LABEL_REPEATED:
+ printer->Print(
+ "for ($type$ element : get$name$List()) {\n"
+ " if (!element.isInitialized()) return false;\n"
+ "}\n",
+ "type", ClassName(field->message_type()),
+ "name", UnderscoresToCapitalizedCamelCase(field));
+ break;
+ }
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "if (!extensionsAreInitialized()) return false;\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " return true;\n"
+ "}\n"
+ "\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
new file mode 100644
index 00000000..d9f8798e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageGenerator {
+ public:
+ explicit MessageGenerator(const Descriptor* descriptor);
+ ~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.
+ void GenerateStaticVariables(io::Printer* printer);
+
+ // Generate the class itself.
+ void Generate(io::Printer* printer);
+
+ private:
+ void GenerateMessageSerializationMethods(io::Printer* printer);
+ void GenerateParseFromMethods(io::Printer* printer);
+ void GenerateSerializeOneField(io::Printer* printer,
+ const FieldDescriptor* field);
+ void GenerateSerializeOneExtensionRange(
+ io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+ void GenerateBuilder(io::Printer* printer);
+ void GenerateCommonBuilderMethods(io::Printer* printer);
+ void GenerateBuilderParsingMethods(io::Printer* printer);
+ void GenerateIsInitialized(io::Printer* printer);
+
+ const Descriptor* descriptor_;
+ FieldGeneratorMap field_generators_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
new file mode 100644
index 00000000..16ddb0d6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -0,0 +1,302 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
+// repeat code between this and the other field types.
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["name"] =
+ UnderscoresToCamelCase(descriptor);
+ (*variables)["capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(descriptor);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["type"] = ClassName(descriptor->message_type());
+ (*variables)["group_or_message"] =
+ (descriptor->type() == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message";
+}
+
+} // namespace
+
+// ===================================================================
+
+MessageFieldGenerator::
+MessageFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private boolean has$capitalized_name$;\n"
+ "private $type$ $name$_ = $type$.getDefaultInstance();\n"
+ "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+ "public $type$ get$capitalized_name$() { return $name$_; }\n");
+}
+
+void MessageFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return result.has$capitalized_name$();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " return result.get$capitalized_name$();\n"
+ "}\n"
+ "public Builder set$capitalized_name$($type$ value) {\n"
+ " result.has$capitalized_name$ = true;\n"
+ " result.$name$_ = value;\n"
+ " return this;\n"
+ "}\n"
+ "public Builder set$capitalized_name$($type$.Builder builderForValue) {\n"
+ " result.has$capitalized_name$ = true;\n"
+ " result.$name$_ = builderForValue.build();\n"
+ " return this;\n"
+ "}\n"
+ "public Builder merge$capitalized_name$($type$ value) {\n"
+ " if (result.has$capitalized_name$() &&\n"
+ " result.$name$_ != $type$.getDefaultInstance()) {\n"
+ " result.$name$_ =\n"
+ " $type$.newBuilder(result.$name$_).mergeFrom(value).buildPartial();\n"
+ " } else {\n"
+ " result.$name$_ = value;\n"
+ " }\n"
+ " result.has$capitalized_name$ = true;\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.has$capitalized_name$ = false;\n"
+ " result.$name$_ = $type$.getDefaultInstance();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " merge$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // Nothing to do for singular fields.
+}
+
+void MessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$.Builder subBuilder = $type$.newBuilder();\n"
+ "if (has$capitalized_name$()) {\n"
+ " subBuilder.mergeFrom(get$capitalized_name$());\n"
+ "}\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(subBuilder, extensionRegistry);\n");
+ }
+
+ printer->Print(variables_,
+ "set$capitalized_name$(subBuilder.buildPartial());\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " output.write$group_or_message$($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+string MessageFieldGenerator::GetBoxedType() const {
+ return ClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private java.util.List<$type$> $name$_ =\n"
+ " java.util.Collections.emptyList();\n"
+ "public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return $name$_;\n" // note: unmodifiable list
+ "}\n"
+ "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ 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.
+ "public java.util.List<$type$> get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return result.get$capitalized_name$Count();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return result.get$capitalized_name$(index);\n"
+ "}\n"
+ "public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ " result.$name$_.set(index, value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder set$capitalized_name$(int index, "
+ "$type$.Builder builderForValue) {\n"
+ " result.$name$_.set(index, builderForValue.build());\n"
+ " return this;\n"
+ "}\n"
+ "public Builder add$capitalized_name$($type$ value) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " result.$name$_.add(value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder add$capitalized_name$($type$.Builder builderForValue) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " result.$name$_.add(builderForValue.build());\n"
+ " return this;\n"
+ "}\n"
+ "public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $type$> values) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " super.addAll(values, result.$name$_);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.$name$_ = java.util.Collections.emptyList();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$type$>();\n"
+ " }\n"
+ " result.$name$_.addAll(other.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
+ " result.$name$_ =\n"
+ " java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$type$.Builder subBuilder = $type$.newBuilder();\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup($number$, subBuilder, extensionRegistry);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(subBuilder, extensionRegistry);\n");
+ }
+
+ printer->Print(variables_,
+ "add$capitalized_name$(subBuilder.buildPartial());\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.write$group_or_message$($number$, element);\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$group_or_message$Size($number$, element);\n"
+ "}\n");
+}
+
+string RepeatedMessageFieldGenerator::GetBoxedType() const {
+ return ClassName(descriptor_->message_type());
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
new file mode 100644
index 00000000..52cf7d15
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+ ~MessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedMessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
new file mode 100644
index 00000000..9138f2c9
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -0,0 +1,365 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const char* PrimitiveTypeName(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return "int";
+ case JAVATYPE_LONG : return "long";
+ case JAVATYPE_FLOAT : return "float";
+ case JAVATYPE_DOUBLE : return "double";
+ case JAVATYPE_BOOLEAN: return "boolean";
+ case JAVATYPE_STRING : return "java.lang.String";
+ case JAVATYPE_BYTES : return "com.google.protobuf.ByteString";
+ case JAVATYPE_ENUM : return NULL;
+ case JAVATYPE_MESSAGE: return NULL;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+const char* 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" ;
+
+ // 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 AllPrintableAscii(const string& text) {
+ // Cannot use isprint() because it's locale-specific. :(
+ for (int i = 0; i < text.size(); i++) {
+ if ((text[i] < 0x20) || text[i] >= 0x7F) {
+ return false;
+ }
+ }
+ return true;
+}
+
+string DefaultValue(const FieldDescriptor* field) {
+ // 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:
+ return SimpleItoa(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ // Need to print as a signed int since Java has no unsigned.
+ return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
+ case FieldDescriptor::CPPTYPE_INT64:
+ return SimpleItoa(field->default_value_int64()) + "L";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
+ "L";
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return SimpleDtoa(field->default_value_double()) + "D";
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return SimpleFtoa(field->default_value_float()) + "F";
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "true" : "false";
+ case FieldDescriptor::CPPTYPE_STRING: {
+ bool isBytes = field->type() == FieldDescriptor::TYPE_BYTES;
+
+ if (!isBytes && AllPrintableAscii(field->default_value_string())) {
+ // All chars are ASCII and printable. In this case CEscape() works
+ // fine (it will only escape quotes and backslashes).
+ // Note: If this "optimization" is removed, DescriptorProtos will
+ // no longer be able to initialize itself due to bootstrapping
+ // problems.
+ return "\"" + CEscape(field->default_value_string()) + "\"";
+ }
+
+ if (isBytes && !field->has_default_value()) {
+ return "com.google.protobuf.ByteString.EMPTY";
+ }
+
+ // Escaping strings correctly for Java and generating efficient
+ // initializers for ByteStrings are both tricky. We can sidestep the
+ // whole problem by just grabbing the default value from the descriptor.
+ return strings::Substitute(
+ "(($0) $1.getDescriptor().getFields().get($2).getDefaultValue())",
+ isBytes ? "com.google.protobuf.ByteString" : "java.lang.String",
+ ClassName(field->containing_type()), field->index());
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables) {
+ (*variables)["name"] =
+ UnderscoresToCamelCase(descriptor);
+ (*variables)["capitalized_name"] =
+ UnderscoresToCapitalizedCamelCase(descriptor);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+ (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ (*variables)["default"] = DefaultValue(descriptor);
+ (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
+}
+
+} // namespace
+
+// ===================================================================
+
+PrimitiveFieldGenerator::
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+void PrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private boolean has$capitalized_name$;\n"
+ "private $type$ $name$_ = $default$;\n"
+ "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+ "public $type$ get$capitalized_name$() { return $name$_; }\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$() {\n"
+ " return result.has$capitalized_name$();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " return result.get$capitalized_name$();\n"
+ "}\n"
+ "public Builder set$capitalized_name$($type$ value) {\n"
+ " result.has$capitalized_name$ = true;\n"
+ " result.$name$_ = value;\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.has$capitalized_name$ = false;\n"
+ " result.$name$_ = $default$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (other.has$capitalized_name$()) {\n"
+ " set$capitalized_name$(other.get$capitalized_name$());\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ // Nothing to do here for primitive types.
+}
+
+void PrimitiveFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "set$capitalized_name$(input.read$capitalized_type$());\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " output.write$capitalized_type$($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (has$capitalized_name$()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$Size($number$, get$capitalized_name$());\n"
+ "}\n");
+}
+
+string PrimitiveFieldGenerator::GetBoxedType() const {
+ return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
+ : descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, &variables_);
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "private java.util.List<$boxed_type$> $name$_ =\n"
+ " java.util.Collections.emptyList();\n"
+ "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
+ " return $name$_;\n" // note: unmodifiable list
+ "}\n"
+ "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return $name$_.get(index);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+ 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.
+ "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
+ " return java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return result.get$capitalized_name$Count();\n"
+ "}\n"
+ "public $type$ get$capitalized_name$(int index) {\n"
+ " return result.get$capitalized_name$(index);\n"
+ "}\n"
+ "public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ " result.$name$_.set(index, value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder add$capitalized_name$($type$ value) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " }\n"
+ " result.$name$_.add(value);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder addAll$capitalized_name$(\n"
+ " java.lang.Iterable<? extends $boxed_type$> values) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " }\n"
+ " super.addAll(values, result.$name$_);\n"
+ " return this;\n"
+ "}\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " result.$name$_ = java.util.Collections.emptyList();\n"
+ " return this;\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!other.$name$_.isEmpty()) {\n"
+ " if (result.$name$_.isEmpty()) {\n"
+ " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+ " }\n"
+ " result.$name$_.addAll(other.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
+ " result.$name$_ =\n"
+ " java.util.Collections.unmodifiableList(result.$name$_);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "add$capitalized_name$(input.read$capitalized_type$());\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.write$capitalized_type$($number$, element);\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$Size($number$, element);\n"
+ "}\n");
+}
+
+string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
+ return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
new file mode 100644
index 00000000..6fe9177a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ ~PrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+ ~RepeatedPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer) const;
+ void GenerateBuilderMembers(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateBuildingCode(io::Printer* printer) const;
+ void GenerateParsingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ string GetBoxedType() const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
new file mode 100644
index 00000000..8cb06270
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -0,0 +1,225 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_service.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
+ : descriptor_(descriptor) {}
+
+ServiceGenerator::~ServiceGenerator() {}
+
+void ServiceGenerator::Generate(io::Printer* printer) {
+ bool is_own_file = descriptor_->file()->options().java_multiple_files();
+ printer->Print(
+ "public $static$ abstract class $classname$\n"
+ " implements com.google.protobuf.Service {\n",
+ "static", is_own_file ? "" : "static",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Generate abstract method declarations.
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ map<string, string> vars;
+ vars["name"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ printer->Print(vars,
+ "public abstract void $name$(\n"
+ " com.google.protobuf.RpcController controller,\n"
+ " $input$ request,\n"
+ " com.google.protobuf.RpcCallback<$output$> done);\n");
+ }
+
+ // Generate getDescriptor() and getDescriptorForType().
+ printer->Print(
+ "\n"
+ "public static final\n"
+ " com.google.protobuf.Descriptors.ServiceDescriptor\n"
+ " getDescriptor() {\n"
+ " return $file$.getDescriptor().getServices().get($index$);\n"
+ "}\n"
+ "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
+ " getDescriptorForType() {\n"
+ " return getDescriptor();\n"
+ "}\n",
+ "file", ClassName(descriptor_->file()),
+ "index", SimpleItoa(descriptor_->index()));
+
+ // Generate more stuff.
+ GenerateCallMethod(printer);
+ GenerateGetPrototype(REQUEST, printer);
+ GenerateGetPrototype(RESPONSE, printer);
+ GenerateStub(printer);
+
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void ServiceGenerator::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);
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(i);
+ vars["method"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ 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.RuntimeException(\"Can't get here.\");\n");
+
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ "}\n"
+ "\n");
+}
+
+void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
+ io::Printer* printer) {
+ 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);
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(i);
+ vars["type"] = ClassName(
+ (which == REQUEST) ? method->input_type() : method->output_type());
+ printer->Print(vars,
+ "case $index$:\n"
+ " return $type$.getDefaultInstance();\n");
+ }
+
+ printer->Print(
+ "default:\n"
+ " throw new java.lang.RuntimeException(\"Can't get here.\");\n");
+
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ "}\n"
+ "\n");
+}
+
+void ServiceGenerator::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$ {\n",
+ "classname", ClassName(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);
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(i);
+ vars["method"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ printer->Print(vars,
+ "\n"
+ "public void $method$(\n"
+ " com.google.protobuf.RpcController controller,\n"
+ " $input$ request,\n"
+ " com.google.protobuf.RpcCallback<$output$> done) {\n"
+ " 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"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
new file mode 100644
index 00000000..adf3dfd4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -0,0 +1,66 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ServiceGenerator {
+ public:
+ explicit ServiceGenerator(const ServiceDescriptor* descriptor);
+ ~ServiceGenerator();
+
+ void Generate(io::Printer* printer);
+
+ private:
+ // Generate the implementation of Service.callMethod().
+ void GenerateCallMethod(io::Printer* printer);
+
+ // Generate the implementations of Service.get{Request,Response}Prototype().
+ enum RequestOrResponse { REQUEST, RESPONSE };
+ void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
+
+ // Generate a stub implementation of the service.
+ void GenerateStub(io::Printer* printer);
+
+ const ServiceDescriptor* descriptor_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+#endif // NET_PROTO2_COMPILER_JAVA_SERVICE_H__
+} // namespace google
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
new file mode 100644
index 00000000..a5a28349
--- /dev/null
+++ b/src/google/protobuf/compiler/main.cc
@@ -0,0 +1,46 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/cpp/cpp_generator.h>
+#include <google/protobuf/compiler/python/python_generator.h>
+#include <google/protobuf/compiler/java/java_generator.h>
+
+
+int main(int argc, char* argv[]) {
+
+ google::protobuf::compiler::CommandLineInterface cli;
+
+ // Proto2 C++
+ google::protobuf::compiler::cpp::CppGenerator cpp_generator;
+ cli.RegisterGenerator("--cpp_out", &cpp_generator,
+ "Generate C++ header and source.");
+
+ // Proto2 Java
+ google::protobuf::compiler::java::JavaGenerator java_generator;
+ cli.RegisterGenerator("--java_out", &java_generator,
+ "Generate Java source file.");
+
+
+ // Proto2 Python
+ google::protobuf::compiler::python::Generator py_generator;
+ cli.RegisterGenerator("--python_out", &py_generator,
+ "Generate Python source file.");
+
+ return cli.Run(argc, argv);
+}
diff --git a/src/google/protobuf/compiler/package_info.h b/src/google/protobuf/compiler/package_info.h
new file mode 100644
index 00000000..aa0c2823
--- /dev/null
+++ b/src/google/protobuf/compiler/package_info.h
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 00000000..622895ff
--- /dev/null
+++ b/src/google/protobuf/compiler/parser.cc
@@ -0,0 +1,1105 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/stubs/hash.h>
+#include <float.h>
+
+
+#include <google/protobuf/compiler/parser.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map-util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+using internal::WireFormat;
+
+namespace {
+
+typedef hash_map<string, FieldDescriptorProto::Type> TypeNameMap;
+
+TypeNameMap MakeTypeNameTable() {
+ 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;
+}
+
+const TypeNameMap kTypeNames = MakeTypeNameTable();
+
+} // 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_(NULL),
+ error_collector_(NULL),
+ source_location_table_(NULL),
+ had_errors_(false),
+ require_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) {
+ if (TryConsume(text)) {
+ return true;
+ } else {
+ AddError("Expected \"" + string(text) + "\".");
+ return false;
+ }
+}
+
+bool Parser::ConsumeIdentifier(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 value = 0;
+ if (!io::Tokenizer::ParseInteger(input_->current().text,
+ kint32max, &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::ConsumeInteger64(uint64 max_value, uint64* 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 value = 0;
+ if (!io::Tokenizer::ParseInteger(input_->current().text,
+ kuint64max, &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 {
+ AddError(error);
+ return false;
+ }
+}
+
+bool Parser::ConsumeString(string* output, const char* error) {
+ if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ io::Tokenizer::ParseString(input_->current().text, output);
+ input_->Next();
+ return true;
+ } else {
+ AddError(error);
+ return false;
+ }
+}
+
+// -------------------------------------------------------------------
+
+void Parser::AddError(int line, int column, const string& error) {
+ if (error_collector_ != NULL) {
+ error_collector_->AddError(line, column, error);
+ }
+ had_errors_ = true;
+}
+
+void Parser::AddError(const string& error) {
+ AddError(input_->current().line, input_->current().column, error);
+}
+
+void Parser::RecordLocation(
+ const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ int line, int column) {
+ if (source_location_table_ != NULL) {
+ source_location_table_->Add(descriptor, location, line, column);
+ }
+}
+
+void Parser::RecordLocation(
+ const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location) {
+ RecordLocation(descriptor, location,
+ input_->current().line, input_->current().column);
+}
+
+// -------------------------------------------------------------------
+
+void Parser::SkipStatement() {
+ while (true) {
+ if (AtEnd()) {
+ return;
+ } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
+ if (TryConsume(";")) {
+ 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 (TryConsume("}")) {
+ return;
+ } else if (TryConsume("{")) {
+ SkipRestOfBlock();
+ }
+ }
+ input_->Next();
+ }
+}
+
+// ===================================================================
+
+bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
+ input_ = input;
+ had_errors_ = false;
+ syntax_identifier_.clear();
+
+ if (LookingAtType(io::Tokenizer::TYPE_START)) {
+ // Advance to first token.
+ input_->Next();
+ }
+
+ if (require_syntax_identifier_ || LookingAt("syntax")) {
+ if (!ParseSyntaxIdentifier()) {
+ // Don't attempt to parse the file if we didn't recognize the syntax
+ // identifier.
+ return false;
+ }
+ } else {
+ syntax_identifier_ = "proto2";
+ }
+
+ // Repeatedly parse statemetns until we reach the end of the file.
+ while (!AtEnd()) {
+ if (!ParseTopLevelStatement(file)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+
+ if (LookingAt("}")) {
+ AddError("Unmatched \"}\".");
+ input_->Next();
+ }
+ }
+ }
+
+ input_ = NULL;
+ return !had_errors_;
+}
+
+bool Parser::ParseSyntaxIdentifier() {
+ DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'."));
+ DO(Consume("="));
+ io::Tokenizer::Token syntax_token = input_->current();
+ string syntax;
+ DO(ConsumeString(&syntax, "Expected syntax identifier."));
+ DO(Consume(";"));
+
+ syntax_identifier_ = syntax;
+
+ if (syntax != "proto2") {
+ AddError(syntax_token.line, syntax_token.column,
+ "Unrecognized syntax identifier \"" + syntax + "\". This parser "
+ "only recognizes \"proto2\".");
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::ParseTopLevelStatement(FileDescriptorProto* file) {
+ if (TryConsume(";")) {
+ // empty statement; ignore
+ return true;
+ } else if (LookingAt("message")) {
+ return ParseMessageDefinition(file->add_message_type());
+ } else if (LookingAt("enum")) {
+ return ParseEnumDefinition(file->add_enum_type());
+ } else if (LookingAt("service")) {
+ return ParseServiceDefinition(file->add_service());
+ } else if (LookingAt("extend")) {
+ return ParseExtend(file->mutable_extension(),
+ file->mutable_message_type());
+ } else if (LookingAt("import")) {
+ return ParseImport(file->add_dependency());
+ } else if (LookingAt("package")) {
+ return ParsePackage(file);
+ } else if (LookingAt("option")) {
+ return ParseOption(file->mutable_options());
+ } else {
+ AddError("Expected top-level statement (e.g. \"message\").");
+ return false;
+ }
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+bool Parser::ParseMessageDefinition(DescriptorProto* message) {
+ DO(Consume("message"));
+ RecordLocation(message, DescriptorPool::ErrorCollector::NAME);
+ DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
+ DO(ParseMessageBlock(message));
+ return true;
+}
+
+bool Parser::ParseMessageBlock(DescriptorProto* message) {
+ DO(Consume("{"));
+
+ while (!TryConsume("}")) {
+ if (AtEnd()) {
+ AddError("Reached end of input in message definition (missing '}').");
+ return false;
+ }
+
+ if (!ParseMessageStatement(message)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+ }
+ }
+
+ return true;
+}
+
+bool Parser::ParseMessageStatement(DescriptorProto* message) {
+ if (TryConsume(";")) {
+ // empty statement; ignore
+ return true;
+ } else if (LookingAt("message")) {
+ return ParseMessageDefinition(message->add_nested_type());
+ } else if (LookingAt("enum")) {
+ return ParseEnumDefinition(message->add_enum_type());
+ } else if (LookingAt("extensions")) {
+ return ParseExtensions(message);
+ } else if (LookingAt("extend")) {
+ return ParseExtend(message->mutable_extension(),
+ message->mutable_nested_type());
+ } else if (LookingAt("option")) {
+ return ParseOption(message->mutable_options());
+ } else {
+ return ParseMessageField(message->add_field(),
+ message->mutable_nested_type());
+ }
+}
+
+bool Parser::ParseMessageField(FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages) {
+ // Parse label and type.
+ FieldDescriptorProto::Label label;
+ DO(ParseLabel(&label));
+ field->set_label(label);
+
+ RecordLocation(field, DescriptorPool::ErrorCollector::TYPE);
+ FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
+ string type_name;
+ DO(ParseType(&type, &type_name));
+ if (type_name.empty()) {
+ field->set_type(type);
+ } else {
+ field->set_type_name(type_name);
+ }
+
+ // Parse name and '='.
+ RecordLocation(field, DescriptorPool::ErrorCollector::NAME);
+ io::Tokenizer::Token name_token = input_->current();
+ DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
+ DO(Consume("=", "Missing field number."));
+
+ // Parse field number.
+ RecordLocation(field, DescriptorPool::ErrorCollector::NUMBER);
+ int number;
+ DO(ConsumeInteger(&number, "Expected field number."));
+ field->set_number(number);
+
+ // Parse options.
+ DO(ParseFieldOptions(field));
+
+ // Deal with groups.
+ if (type_name.empty() && type == FieldDescriptorProto::TYPE_GROUP) {
+ DescriptorProto* group = messages->Add();
+ group->set_name(field->name());
+ // Record name location to match the field name's location.
+ RecordLocation(group, DescriptorPool::ErrorCollector::NAME,
+ name_token.line, name_token.column);
+
+ // 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));
+ } else {
+ AddError("Missing group body.");
+ return false;
+ }
+ } else {
+ DO(Consume(";"));
+ }
+
+ return true;
+}
+
+bool Parser::ParseFieldOptions(FieldDescriptorProto* field) {
+ if (!TryConsume("[")) return true;
+
+ // Parse field options.
+ do {
+ if (LookingAt("default")) {
+ DO(ParseDefaultAssignment(field));
+ } else {
+ DO(ParseOptionAssignment(field->mutable_options()));
+ }
+ } while (TryConsume(","));
+
+ DO(Consume("]"));
+ return true;
+}
+
+bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field) {
+ if (field->has_default_value()) {
+ AddError("Already set option \"default\".");
+ field->clear_default_value();
+ }
+
+ DO(Consume("default"));
+ DO(Consume("="));
+
+ RecordLocation(field, DescriptorPool::ErrorCollector::DEFAULT_VALUE);
+ 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. Assume an enum for now.
+ DO(ConsumeIdentifier(default_value, "Expected identifier."));
+ 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 max_value = kint64max;
+ if (field->type() == FieldDescriptorProto::TYPE_INT32 ||
+ field->type() == FieldDescriptorProto::TYPE_SINT32 ||
+ field->type() == FieldDescriptorProto::TYPE_SFIXED32) {
+ max_value = kint32max;
+ }
+
+ // 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 value;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ // And stringify it again.
+ default_value->append(SimpleItoa(value));
+ break;
+ }
+
+ case FieldDescriptorProto::TYPE_UINT32:
+ case FieldDescriptorProto::TYPE_UINT64:
+ case FieldDescriptorProto::TYPE_FIXED32:
+ case FieldDescriptorProto::TYPE_FIXED64: {
+ uint64 max_value = kuint64max;
+ if (field->type() == FieldDescriptorProto::TYPE_UINT32 ||
+ field->type() == FieldDescriptorProto::TYPE_FIXED32) {
+ max_value = kuint32max;
+ }
+
+ // 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 value;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ // And stringify it again.
+ default_value->append(SimpleItoa(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:
+ DO(ConsumeString(default_value, "Expected string."));
+ 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 identifier."));
+ break;
+
+ case FieldDescriptorProto::TYPE_MESSAGE:
+ case FieldDescriptorProto::TYPE_GROUP:
+ AddError("Messages can't have default values.");
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::ParseOptionAssignment(Message* options) {
+ Message::Reflection* reflection = options->GetReflection();
+ const Descriptor* descriptor = options->GetDescriptor();
+
+ // Parse name.
+ string name;
+ int line = input_->current().line;
+ int column = input_->current().column;
+ DO(ConsumeIdentifier(&name, "Expected option name."));
+
+ // Is it valid?
+ const FieldDescriptor* field = descriptor->FindFieldByName(name);
+ if (field == NULL) {
+ AddError(line, column, "Unknown option: " + name);
+ return false;
+ }
+ if (field->is_repeated()) {
+ AddError(line, column, "Not implemented: repeated options.");
+ return false;
+ }
+ if (reflection->HasField(field)) {
+ AddError(line, column, "Option \"" + name + "\" was already set.");
+ return false;
+ }
+
+ // Are we trying to assign a member of a message?
+ if (LookingAt(".")) {
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ AddError("Option \"" + name + "\" is an atomic type, not a message.");
+ return false;
+ }
+ DO(Consume("."));
+
+ // This field is a message/group. The user must identify a field within
+ // it to set.
+ return ParseOptionAssignment(reflection->MutableMessage(field));
+ }
+
+ DO(Consume("="));
+
+ // Parse the option value.
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ uint64 value;
+ bool is_negative = TryConsume("-");
+ uint64 max_value = kint32max;
+ if (is_negative) ++max_value;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ reflection->SetInt32(field, is_negative ? -value : value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_INT64: {
+ uint64 value;
+ bool is_negative = TryConsume("-");
+ uint64 max_value = kint64max;
+ if (is_negative) ++max_value;
+ DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+ reflection->SetInt64(field, is_negative ? -value : value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ uint64 value;
+ DO(ConsumeInteger64(kuint32max, &value, "Expected integer."));
+ reflection->SetUInt32(field, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ uint64 value;
+ DO(ConsumeInteger64(kuint64max, &value, "Expected integer."));
+ reflection->SetUInt64(field, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value;
+ bool is_negative = TryConsume("-");
+ DO(ConsumeNumber(&value, "Expected number."));
+ reflection->SetDouble(field, is_negative ? -value : value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ double value;
+ bool is_negative = TryConsume("-");
+ DO(ConsumeNumber(&value, "Expected number."));
+ reflection->SetFloat(field, is_negative ? -value : value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_BOOL:
+ if (TryConsume("true")) {
+ reflection->SetBool(field, true);
+ } else if (TryConsume("false")) {
+ reflection->SetBool(field, false);
+ } else {
+ AddError("Expected \"true\" or \"false\".");
+ return false;
+ }
+ break;
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ string value_name;
+ int value_line = input_->current().line;
+ int value_column = input_->current().column;
+ DO(ConsumeIdentifier(&value_name, "Expected enum value."));
+ const EnumValueDescriptor* value =
+ field->enum_type()->FindValueByName(value_name);
+ if (value == NULL) {
+ AddError(value_line, value_column,
+ "Enum type \"" + field->enum_type()->full_name() + "\" has no value "
+ "named \"" + value_name + "\".");
+ return false;
+ }
+ reflection->SetEnum(field, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string value;
+ DO(ConsumeString(&value, "Expected string."));
+ reflection->SetString(field, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ // TODO(kenton): Allow use of protocol buffer text format here?
+ AddError("\"" + name + "\" is a message. To set fields within it, use "
+ "syntax like \"" + name + ".foo = value\".");
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool Parser::ParseExtensions(DescriptorProto* message) {
+ // Parse the declaration.
+ DO(Consume("extensions"));
+
+ do {
+ DescriptorProto::ExtensionRange* range = message->add_extension_range();
+ RecordLocation(range, DescriptorPool::ErrorCollector::NUMBER);
+
+ int start, end;
+ DO(ConsumeInteger(&start, "Expected field number range."));
+
+ if (TryConsume("to")) {
+ if (TryConsume("max")) {
+ end = FieldDescriptor::kMaxNumber;
+ } else {
+ DO(ConsumeInteger(&end, "Expected integer."));
+ }
+ } else {
+ 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(","));
+
+ DO(Consume(";"));
+ return true;
+}
+
+bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
+ RepeatedPtrField<DescriptorProto>* messages) {
+ DO(Consume("extend"));
+
+ // We expect to see at least one extension field defined in the extend block.
+ // We need to create it now so we can record the extendee's location.
+ FieldDescriptorProto* first_field = extensions->Add();
+
+ // Parse the extendee type.
+ RecordLocation(first_field, DescriptorPool::ErrorCollector::EXTENDEE);
+ DO(ParseUserDefinedType(first_field->mutable_extendee()));
+
+ // Parse the block.
+ DO(Consume("{"));
+
+ bool is_first = true;
+
+ do {
+ if (AtEnd()) {
+ AddError("Reached end of input in extend definition (missing '}').");
+ return false;
+ }
+
+ FieldDescriptorProto* field;
+ if (is_first) {
+ field = first_field;
+ is_first = false;
+ } else {
+ field = extensions->Add();
+ field->set_extendee(first_field->extendee());
+ }
+
+ if (!ParseMessageField(field, messages)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+ }
+ } while(!TryConsume("}"));
+
+ return true;
+}
+
+// -------------------------------------------------------------------
+// Enums
+
+bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type) {
+ DO(Consume("enum"));
+ RecordLocation(enum_type, DescriptorPool::ErrorCollector::NAME);
+ DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
+ DO(ParseEnumBlock(enum_type));
+ return true;
+}
+
+bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type) {
+ DO(Consume("{"));
+
+ while (!TryConsume("}")) {
+ if (AtEnd()) {
+ AddError("Reached end of input in enum definition (missing '}').");
+ return false;
+ }
+
+ if (!ParseEnumStatement(enum_type)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+ }
+ }
+
+ return true;
+}
+
+bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type) {
+ if (TryConsume(";")) {
+ // empty statement; ignore
+ return true;
+ } else if (LookingAt("option")) {
+ return ParseOption(enum_type->mutable_options());
+ } else {
+ return ParseEnumConstant(enum_type->add_value());
+ }
+}
+
+bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value) {
+ RecordLocation(enum_value, DescriptorPool::ErrorCollector::NAME);
+ DO(ConsumeIdentifier(enum_value->mutable_name(),
+ "Expected enum constant name."));
+ DO(Consume("=", "Missing numeric value for enum constant."));
+
+ bool is_negative = TryConsume("-");
+ int number;
+ DO(ConsumeInteger(&number, "Expected integer."));
+ if (is_negative) number *= -1;
+ enum_value->set_number(number);
+
+ // TODO(kenton): Options for enum values?
+
+ DO(Consume(";"));
+
+ return true;
+}
+
+// -------------------------------------------------------------------
+// Services
+
+bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service) {
+ DO(Consume("service"));
+ RecordLocation(service, DescriptorPool::ErrorCollector::NAME);
+ DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
+ DO(ParseServiceBlock(service));
+ return true;
+}
+
+bool Parser::ParseServiceBlock(ServiceDescriptorProto* service) {
+ DO(Consume("{"));
+
+ while (!TryConsume("}")) {
+ if (AtEnd()) {
+ AddError("Reached end of input in service definition (missing '}').");
+ return false;
+ }
+
+ if (!ParseServiceStatement(service)) {
+ // This statement failed to parse. Skip it, but keep looping to parse
+ // other statements.
+ SkipStatement();
+ }
+ }
+
+ return true;
+}
+
+bool Parser::ParseServiceStatement(ServiceDescriptorProto* service) {
+ if (TryConsume(";")) {
+ // empty statement; ignore
+ return true;
+ } else if (LookingAt("option")) {
+ return ParseOption(service->mutable_options());
+ } else {
+ return ParseServiceMethod(service->add_method());
+ }
+}
+
+bool Parser::ParseServiceMethod(MethodDescriptorProto* method) {
+ DO(Consume("rpc"));
+ RecordLocation(method, DescriptorPool::ErrorCollector::NAME);
+ DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
+
+ // Parse input type.
+ DO(Consume("("));
+ RecordLocation(method, DescriptorPool::ErrorCollector::INPUT_TYPE);
+ DO(ParseUserDefinedType(method->mutable_input_type()));
+ DO(Consume(")"));
+
+ // Parse output type.
+ DO(Consume("returns"));
+ DO(Consume("("));
+ RecordLocation(method, DescriptorPool::ErrorCollector::OUTPUT_TYPE);
+ DO(ParseUserDefinedType(method->mutable_output_type()));
+ DO(Consume(")"));
+
+ if (TryConsume("{")) {
+ // Options!
+ while (!TryConsume("}")) {
+ if (AtEnd()) {
+ AddError("Reached end of input in method options (missing '}').");
+ return false;
+ }
+
+ if (TryConsume(";")) {
+ // empty statement; ignore
+ } else {
+ if (!ParseOption(method->mutable_options())) {
+ // This statement failed to parse. Skip it, but keep looping to
+ // parse other statements.
+ SkipStatement();
+ }
+ }
+ }
+ } else {
+ DO(Consume(";"));
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------
+
+bool Parser::ParseLabel(FieldDescriptorProto::Label* label) {
+ if (TryConsume("optional")) {
+ *label = FieldDescriptorProto::LABEL_OPTIONAL;
+ return true;
+ } else if (TryConsume("repeated")) {
+ *label = FieldDescriptorProto::LABEL_REPEATED;
+ return true;
+ } else if (TryConsume("required")) {
+ *label = FieldDescriptorProto::LABEL_REQUIRED;
+ return true;
+ } else {
+ AddError("Expected \"required\", \"optional\", or \"repeated\".");
+ // We can actually reasonably recover here by just assuming the user
+ // forgot the label altogether.
+ *label = FieldDescriptorProto::LABEL_OPTIONAL;
+ return true;
+ }
+}
+
+bool Parser::ParseType(FieldDescriptorProto::Type* type,
+ string* type_name) {
+ TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
+ if (iter != kTypeNames.end()) {
+ *type = iter->second;
+ input_->Next();
+ } else {
+ DO(ParseUserDefinedType(type_name));
+ }
+ return true;
+}
+
+bool Parser::ParseUserDefinedType(string* type_name) {
+ type_name->clear();
+
+ TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
+ if (iter != kTypeNames.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.
+ 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) {
+ if (file->has_package()) {
+ AddError("Multiple package definitions.");
+ }
+
+ DO(Consume("package"));
+
+ RecordLocation(file, DescriptorPool::ErrorCollector::NAME);
+
+ while (true) {
+ string identifier;
+ DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+ file->mutable_package()->append(identifier);
+ if (!TryConsume(".")) break;
+ file->mutable_package()->append(".");
+ }
+
+ DO(Consume(";"));
+ return true;
+}
+
+bool Parser::ParseImport(string* import_filename) {
+ DO(Consume("import"));
+ DO(ConsumeString(import_filename,
+ "Expected a string naming the file to import."));
+ DO(Consume(";"));
+ return true;
+}
+
+bool Parser::ParseOption(Message* options) {
+ DO(Consume("option"));
+ DO(ParseOptionAssignment(options));
+ DO(Consume(";"));
+ return true;
+}
+
+// ===================================================================
+
+SourceLocationTable::SourceLocationTable() {}
+SourceLocationTable::~SourceLocationTable() {}
+
+bool SourceLocationTable::Find(
+ const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ int* line, int* column) const {
+ const pair<int, int>* result =
+ FindOrNull(location_map_, make_pair(descriptor, location));
+ if (result == NULL) {
+ *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_[make_pair(descriptor, location)] = 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 00000000..adf6e9b1
--- /dev/null
+++ b/src/google/protobuf/compiler/parser.h
@@ -0,0 +1,301 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <map>
+#include <string>
+#include <utility>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/io/tokenizer.h>
+
+namespace google {
+namespace protobuf { class Message; }
+
+namespace protobuf {
+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 LIBPROTOBUF_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 fetaures:
+
+ // 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;
+ }
+
+ // Requsets 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 string& GetSyntaxIndentifier() { 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;
+ }
+
+ private:
+ // =================================================================
+ // 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(string* output, const char* error);
+ // Consume an integer and store its value in "output".
+ bool ConsumeInteger(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 max_value, uint64* 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(string* output, const char* error);
+
+ // -----------------------------------------------------------------
+ // Error logging helpers
+
+ // Invokes error_collector_->AddError(), if error_collector_ is not NULL.
+ void AddError(int line, int column, const string& error);
+
+ // Invokes error_collector_->AddError() with the line and column number
+ // of the current token.
+ void AddError(const string& error);
+
+ // Record the given line and column and associate it with this descriptor
+ // in the SourceLocationTable.
+ void RecordLocation(const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ int line, int column);
+
+ // Record the current line and column and associate it with this descriptor
+ // in the SourceLocationTable.
+ void RecordLocation(const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location);
+
+ // =================================================================
+ // 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();
+
+ // 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);
+
+ // Parse various language high-level language construrcts.
+ bool ParseMessageDefinition(DescriptorProto* message);
+ bool ParseEnumDefinition(EnumDescriptorProto* enum_type);
+ bool ParseServiceDefinition(ServiceDescriptorProto* service);
+ bool ParsePackage(FileDescriptorProto* file);
+ bool ParseImport(string* import_filename);
+ bool ParseOption(Message* options);
+
+ // 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);
+ bool ParseEnumBlock(EnumDescriptorProto* enum_type);
+ bool ParseServiceBlock(ServiceDescriptorProto* service);
+
+ // Parse one statement within a message, enum, or service block, inclunding
+ // final semicolon.
+ bool ParseMessageStatement(DescriptorProto* message);
+ bool ParseEnumStatement(EnumDescriptorProto* message);
+ bool ParseServiceStatement(ServiceDescriptorProto* message);
+
+ // Parse a field of a message. If the field is a group, its type will be
+ // added to "messages".
+ bool ParseMessageField(FieldDescriptorProto* field,
+ RepeatedPtrField<DescriptorProto>* messages);
+
+ // Parse an "extensions" declaration.
+ bool ParseExtensions(DescriptorProto* message);
+
+ // Parse an "extend" declaration.
+ bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
+ RepeatedPtrField<DescriptorProto>* messages);
+
+ // Parse a single enum value within an enum block.
+ bool ParseEnumConstant(EnumValueDescriptorProto* enum_value);
+
+ // Parse a single method within a service definition.
+ bool ParseServiceMethod(MethodDescriptorProto* method);
+
+ // Parse "required", "optional", or "repeated" and fill in "label"
+ // with the value.
+ bool ParseLabel(FieldDescriptorProto::Label* label);
+
+ // 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,
+ 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(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);
+
+ // Parse the "default" option. This needs special handling because its
+ // type is the field's type.
+ bool ParseDefaultAssignment(FieldDescriptorProto* field);
+
+ // 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 ParseOptionAssignment(Message* options);
+
+ // =================================================================
+
+ io::Tokenizer* input_;
+ io::ErrorCollector* error_collector_;
+ SourceLocationTable* source_location_table_;
+ bool had_errors_;
+ bool require_syntax_identifier_;
+ string syntax_identifier_;
+
+ 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.
+class LIBPROTOBUF_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;
+
+ // Adds a location to the table.
+ void Add(const Message* descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ int line, int column);
+
+ // Clears the contents of the table.
+ void Clear();
+
+ private:
+ typedef map<
+ pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>,
+ pair<int, int> > LocationMap;
+ LocationMap location_map_;
+};
+
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..489106b0
--- /dev/null
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -0,0 +1,1142 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+#include <algorithm>
+
+#include <google/protobuf/compiler/parser.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/wire_format.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/unittest.pb.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 compiler {
+
+namespace {
+
+class MockErrorCollector : public io::ErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(int line, int column, const string& message) {
+ 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() {}
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename,
+ const string& element_name,
+ const Message* descriptor,
+ ErrorLocation location,
+ const string& message) {
+ int line, column;
+ 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_);
+
+ // 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) == NULL);
+ EXPECT_EQ(expected_errors, error_collector_.text_);
+ }
+
+ MockErrorCollector error_collector_;
+ DescriptorPool pool_;
+
+ scoped_ptr<io::ZeroCopyInputStream> raw_input_;
+ scoped_ptr<io::Tokenizer> input_;
+ scoped_ptr<Parser> parser_;
+ bool require_syntax_identifier_;
+};
+
+// ===================================================================
+
+typedef ParserTest ParseMessageTest;
+
+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_->GetSyntaxIndentifier());
+}
+
+TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
+ ExpectParsesTo(
+ "syntax = \"proto2\";\n"
+ "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_->GetSyntaxIndentifier());
+}
+
+TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
+ require_syntax_identifier_ = true;
+ ExpectParsesTo(
+ "syntax = \"proto2\";\n"
+ "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_->GetSyntaxIndentifier());
+}
+
+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 string foo = 1 [default='13\\001'];\n"
+ " required bytes foo = 1 [default='14\\002'];\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_STRING default_value:\"13\\001\" "ETC" }"
+ " field { type:TYPE_BYTES default_value:\"14\\\\002\" "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, FieldOptions) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " optional string foo = 1 [ctype=CORD];\n"
+ "}\n",
+
+ "message_type {"
+ " name: \"TestMessage\""
+ " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_STRING number:1"
+ " options { ctype:CORD } }"
+ "}");
+}
+
+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, 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, 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, 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\" }");
+}
+
+// ===================================================================
+
+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"
+ "}\n",
+
+ "enum_type {"
+ " name: \"TestEnum\""
+ " value { name:\"FOO\" number:13 }"
+ " value { name:\"BAR\" number:-10 }"
+ " value { name:\"BAZ\" number:500 }"
+ "}");
+}
+
+// ===================================================================
+
+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, Methods) {
+ 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, 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 {"
+ " java_package: \"com.google.foo\""
+ " optimize_for: CODE_SIZE"
+ "}");
+}
+
+// TODO(kenton): We'd like to be able to test all possible option types,
+// but we are unable to do so here because we can only test the options
+// that actually exist, which currently doesn't cover everything. Perhaps
+// we can solve this in the future by allowing options to be extended, then
+// defining extensions of every type?
+
+// ===================================================================
+// 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 'syntax = \"proto2\";'.\n");
+ EXPECT_EQ("", parser_->GetSyntaxIndentifier());
+}
+
+TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
+ ExpectHasEarlyExitErrors(
+ "syntax = \"no_such_syntax\";",
+ "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
+ "only recognizes \"proto2\".\n");
+ EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIndentifier());
+}
+
+TEST_F(ParseErrorTest, SimpleSyntaxError) {
+ ExpectHasErrors(
+ "message TestMessage @#$ { blah }",
+ "0:20: Expected \"{\".\n");
+ EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier());
+}
+
+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 option name.\n");
+}
+
+TEST_F(ParseErrorTest, UnknownOption) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [nosuchoption=5];\n"
+ "}\n",
+ "1:27: Unknown option: nosuchoption\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [default=true];\n"
+ "}\n",
+ "1:35: Expected integer.\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.\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, DefaultValueMissing) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [default=];\n"
+ "}\n",
+ "1:35: Expected integer.\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, 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");
+}
+
+// -------------------------------------------------------------------
+// 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");
+}
+
+// -------------------------------------------------------------------
+// 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:37: Unknown option: invalid\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");
+}
+
+// -------------------------------------------------------------------
+// Option errors
+
+TEST_F(ParseErrorTest, OptionWrongType) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional string foo = 1 [ctype=1];\n"
+ "}\n",
+ "1:33: Expected enum value.\n");
+}
+
+TEST_F(ParseErrorTest, DupOption) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [ctype=CORD,ctype=CORD];\n"
+ "}\n",
+ "1:38: Option \"ctype\" was already set.\n");
+}
+
+TEST_F(ParseErrorTest, NotMessageOption) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [ctype.blah=1];\n"
+ "}\n",
+ "1:32: Option \"ctype\" is an atomic type, not a message.\n");
+}
+
+// TODO(kenton): Test errors for all possible option types (see TODO above,
+// under the option parsing tests).
+
+// ===================================================================
+// 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) != NULL);
+
+ // Now try to define it as a package.
+ ExpectHasValidationErrors(
+ "package foo.bar;",
+ "0:8: \"foo\" is already defined (as something other than a package) "
+ "in file \"bar.proto\".\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");
+}
+
+TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
+ ExpectHasValidationErrors(
+ "extend Baz { optional int32 bar = 1; }\n",
+ "0:7: \"Baz\" is not defined.\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, ExtensionRangeNumberError) {
+ ExpectHasValidationErrors(
+ "message Foo {\n"
+ " extensions 0;\n"
+ "}\n",
+ "1:13: Extension numbers must be positive integers.\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, EnumValueNameError) {
+ ExpectHasValidationErrors(
+ "enum Foo {\n"
+ " BAR = 1;\n"
+ " BAR = 1;\n"
+ "}\n",
+ "2:2: \"BAR\" is already defined.\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 that the output from FileDescriptor::DebugString() (and all other
+// descriptor types) is parseable, and results in the same Descriptor
+// definitions again afoter parsing (not, however, that the order of messages
+// cannot be guaranteed to be the same)
+
+typedef ParserTest ParseDecriptorDebugTest;
+
+class CompareDescriptorNames {
+ public:
+ bool operator()(const DescriptorProto* left, const DescriptorProto* right) {
+ 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();
+ 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();
+ sort(data, data + size, CompareDescriptorNames());
+}
+
+TEST_F(ParseDecriptorDebugTest, 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
+ 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("google/protobuf/unittest.proto");
+ // We need the imported dependency before we can build our parsed proto
+ const FileDescriptor* import =
+ protobuf_unittest_import::ImportMessage::descriptor()->file();
+ FileDescriptorProto import_proto;
+ import->CopyTo(&import_proto);
+ ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+ const FileDescriptor* actual = pool_.BuildFile(parsed);
+ parsed.Clear();
+ actual->CopyTo(&parsed);
+ ASSERT_TRUE(actual != NULL);
+
+ // 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());
+}
+
+// ===================================================================
+
+} // anonymous namespace
+
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
new file mode 100644
index 00000000..e1171382
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -0,0 +1,794 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <utility>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/python/python_generator.h>
+#include <google/protobuf/descriptor.pb.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+namespace {
+
+// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
+// suffix stripped.
+// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc.
+string StripProto(const string& filename) {
+ const char* suffix = HasSuffixString(filename, ".protodevel")
+ ? ".protodevel" : ".proto";
+ return StripSuffixString(filename, suffix);
+}
+
+
+// Returns the Python module name expected for a given .proto filename.
+string ModuleName(const string& filename) {
+ string basename = StripProto(filename);
+ StripString(&basename, "-", '_');
+ StripString(&basename, "/", '.');
+ return basename + "_pb2";
+}
+
+
+// Returns the name of all containing types for descriptor,
+// in order from outermost to innermost, followed by descriptor's
+// own name. Each name is separated by |separator|.
+template <typename DescriptorT>
+string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
+ const string& separator) {
+ string name = descriptor.name();
+ for (const Descriptor* current = descriptor.containing_type();
+ current != NULL; current = current->containing_type()) {
+ name = current->name() + separator + name;
+ }
+ return 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";
+
+
+// Prints the common boilerplate needed at the top of every .py
+// 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(
+ "#!/usr/bin/python2.4\n"
+ "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "\n"
+ "from google.protobuf import descriptor\n"
+ "from google.protobuf import message\n"
+ "from google.protobuf import reflection\n"
+ "from google.protobuf import service\n"
+ "from google.protobuf import service_reflection\n");
+ // Avoid circular imports if this module is descriptor_pb2.
+ if (!descriptor_proto) {
+ printer->Print(
+ "from google.protobuf import descriptor_pb2\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
+string StringifyDefaultValue(const FieldDescriptor& field) {
+ if (field.is_repeated()) {
+ return "[]";
+ }
+
+ switch (field.cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return SimpleItoa(field.default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return SimpleItoa(field.default_value_uint32());
+ case FieldDescriptor::CPPTYPE_INT64:
+ return SimpleItoa(field.default_value_int64());
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(field.default_value_uint64());
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return SimpleDtoa(field.default_value_double());
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return SimpleFtoa(field.default_value_float());
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field.default_value_bool() ? "True" : "False";
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return SimpleItoa(field.default_value_enum()->number());
+ case FieldDescriptor::CPPTYPE_STRING:
+ return "\"" + CEscape(field.default_value_string()) + "\"";
+ 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 "";
+}
+
+
+
+} // namespace
+
+
+Generator::Generator() : file_(NULL) {
+}
+
+Generator::~Generator() {
+}
+
+bool Generator::Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const {
+
+ // 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;
+ string module_name = ModuleName(file->name());
+ string filename = module_name;
+ StripString(&filename, ".", '/');
+ filename += ".py";
+
+
+ scoped_ptr<io::ZeroCopyOutputStream> output(output_directory->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
+ printer_ = &printer;
+
+ PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto());
+ PrintTopLevelEnums();
+ PrintTopLevelExtensions();
+ PrintAllNestedEnumsInFile();
+ PrintMessageDescriptors();
+ // We have to print the imports after the descriptors, so that mutually
+ // recursive protos in separate files can successfully reference each other.
+ PrintImports();
+ FixForeignFieldsInDescriptors();
+ PrintMessages();
+ // We have to fix up the extensions after the message classes themselves,
+ // since they need to call static RegisterExtension() methods on these
+ // classes.
+ FixForeignFieldsInExtensions();
+ PrintServices();
+ 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) {
+ string module_name = ModuleName(file_->dependency(i)->name());
+ printer_->Print("import $module$\n", "module",
+ module_name);
+ }
+ printer_->Print("\n");
+}
+
+// Prints descriptors and module-level constants for all top-level
+// enums defined in |file|.
+void Generator::PrintTopLevelEnums() const {
+ vector<pair<string, int> > top_level_enum_values;
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
+ PrintEnum(enum_descriptor);
+ printer_->Print("\n");
+
+ for (int j = 0; j < enum_descriptor.value_count(); ++j) {
+ const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j);
+ top_level_enum_values.push_back(
+ make_pair(value_descriptor.name(), value_descriptor.number()));
+ }
+ }
+
+ for (int i = 0; i < top_level_enum_values.size(); ++i) {
+ printer_->Print("$name$ = $value$\n",
+ "name", top_level_enum_values[i].first,
+ "value", SimpleItoa(top_level_enum_values[i].second));
+ }
+ 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 {
+ map<string, string> m;
+ m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor);
+ m["name"] = enum_descriptor.name();
+ m["full_name"] = enum_descriptor.full_name();
+ m["filename"] = enum_descriptor.name();
+ const char enum_descriptor_template[] =
+ "$descriptor_name$ = descriptor.EnumDescriptor(\n"
+ " name='$name$',\n"
+ " full_name='$full_name$',\n"
+ " filename='$filename$',\n"
+ " values=[\n";
+ string options_string;
+ enum_descriptor.options().SerializeToString(&options_string);
+ printer_->Print(m, enum_descriptor_template);
+ printer_->Indent();
+ printer_->Indent();
+ 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("options=$options_value$,\n",
+ "options_value",
+ OptionsValue("EnumOptions", CEscape(options_string)));
+ printer_->Outdent();
+ printer_->Print(")\n");
+ 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));
+ }
+}
+
+void Generator::PrintTopLevelExtensions() const {
+ const bool is_extension = true;
+ for (int i = 0; i < file_->extension_count(); ++i) {
+ const FieldDescriptor& extension_field = *file_->extension(i);
+ printer_->Print("$name$ = ", "name", extension_field.name());
+ PrintFieldDescriptor(extension_field, is_extension);
+ printer_->Print("\n");
+ }
+ printer_->Print("\n");
+}
+
+// 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::PrintServices() const {
+ for (int i = 0; i < file_->service_count(); ++i) {
+ PrintServiceDescriptor(*file_->service(i));
+ PrintServiceClass(*file_->service(i));
+ PrintServiceStub(*file_->service(i));
+ printer_->Print("\n");
+ }
+}
+
+void Generator::PrintServiceDescriptor(
+ const ServiceDescriptor& descriptor) const {
+ printer_->Print("\n");
+ string service_name = ModuleLevelServiceDescriptorName(descriptor);
+ string options_string;
+ descriptor.options().SerializeToString(&options_string);
+
+ printer_->Print(
+ "$service_name$ = descriptor.ServiceDescriptor(\n",
+ "service_name", service_name);
+ printer_->Indent();
+ map<string, string> m;
+ m["name"] = descriptor.name();
+ m["full_name"] = descriptor.full_name();
+ m["index"] = SimpleItoa(descriptor.index());
+ m["options_value"] = OptionsValue("ServiceOptions", options_string);
+ const char required_function_arguments[] =
+ "name='$name$',\n"
+ "full_name='$full_name$',\n"
+ "index=$index$,\n"
+ "options=$options_value$,\n"
+ "methods=[\n";
+ printer_->Print(m, required_function_arguments);
+ for (int i = 0; i < descriptor.method_count(); ++i) {
+ const MethodDescriptor* method = descriptor.method(i);
+ string options_string;
+ method->options().SerializeToString(&options_string);
+
+ m.clear();
+ m["name"] = method->name();
+ m["full_name"] = method->full_name();
+ m["index"] = SimpleItoa(method->index());
+ m["serialized_options"] = CEscape(options_string);
+ m["input_type"] = ModuleLevelDescriptorName(*(method->input_type()));
+ m["output_type"] = ModuleLevelDescriptorName(*(method->output_type()));
+ m["options_value"] = OptionsValue("MethodOptions", options_string);
+ printer_->Print("descriptor.MethodDescriptor(\n");
+ printer_->Indent();
+ printer_->Print(
+ m,
+ "name='$name$',\n"
+ "full_name='$full_name$',\n"
+ "index=$index$,\n"
+ "containing_service=None,\n"
+ "input_type=$input_type$,\n"
+ "output_type=$output_type$,\n"
+ "options=$options_value$,\n");
+ printer_->Outdent();
+ printer_->Print("),\n");
+ }
+
+ printer_->Outdent();
+ printer_->Print("])\n\n");
+}
+
+void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
+ // Print the service.
+ printer_->Print("class $class_name$(service.Service):\n",
+ "class_name", descriptor.name());
+ printer_->Indent();
+ printer_->Print(
+ "__metaclass__ = service_reflection.GeneratedServiceType\n"
+ "$descriptor_key$ = $descriptor_name$\n",
+ "descriptor_key", kDescriptorKey,
+ "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
+ printer_->Outdent();
+}
+
+void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const {
+ // Print the service stub.
+ printer_->Print("class $class_name$_Stub($class_name$):\n",
+ "class_name", descriptor.name());
+ printer_->Indent();
+ printer_->Print(
+ "__metaclass__ = service_reflection.GeneratedServiceStubType\n"
+ "$descriptor_key$ = $descriptor_name$\n",
+ "descriptor_key", kDescriptorKey,
+ "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
+ 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 {
+ PrintNestedDescriptors(message_descriptor);
+
+ printer_->Print("\n");
+ printer_->Print("$descriptor_name$ = descriptor.Descriptor(\n",
+ "descriptor_name",
+ ModuleLevelDescriptorName(message_descriptor));
+ printer_->Indent();
+ map<string, string> m;
+ m["name"] = message_descriptor.name();
+ m["full_name"] = message_descriptor.full_name();
+ m["filename"] = message_descriptor.file()->name();
+ const char required_function_arguments[] =
+ "name='$name$',\n"
+ "full_name='$full_name$',\n"
+ "filename='$filename$',\n"
+ "containing_type=None,\n"; // TODO(robinson): Implement containing_type.
+ printer_->Print(m, required_function_arguments);
+ PrintFieldsInDescriptor(message_descriptor);
+ PrintExtensionsInDescriptor(message_descriptor);
+ // TODO(robinson): implement printing of nested_types.
+ printer_->Print("nested_types=[], # TODO(robinson): Implement.\n");
+ printer_->Print("enum_types=[\n");
+ printer_->Indent();
+ for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
+ const string descriptor_name = ModuleLevelDescriptorName(
+ *message_descriptor.enum_type(i));
+ printer_->Print(descriptor_name.c_str());
+ printer_->Print(",\n");
+ }
+ printer_->Outdent();
+ printer_->Print("],\n");
+ string options_string;
+ message_descriptor.options().SerializeToString(&options_string);
+ printer_->Print(
+ "options=$options_value$",
+ "options_value", OptionsValue("MessageOptions", options_string));
+ 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) {
+ PrintMessage(*file_->message_type(i));
+ 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().
+void Generator::PrintMessage(
+ const Descriptor& message_descriptor) const {
+ printer_->Print("class $name$(message.Message):\n", "name",
+ message_descriptor.name());
+ printer_->Indent();
+ printer_->Print("__metaclass__ = reflection.GeneratedProtocolMessageType\n");
+ PrintNestedMessages(message_descriptor);
+ map<string, string> m;
+ m["descriptor_key"] = kDescriptorKey;
+ m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
+ printer_->Print(m, "$descriptor_key$ = $descriptor_name$\n");
+ printer_->Outdent();
+}
+
+// Prints all nested messages within |containing_descriptor|.
+// Mutually recursive with PrintMessage().
+void Generator::PrintNestedMessages(
+ const Descriptor& containing_descriptor) const {
+ for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
+ printer_->Print("\n");
+ PrintMessage(*containing_descriptor.nested_type(i));
+ }
+}
+
+// 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.
+void Generator::FixForeignFieldsInDescriptor(
+ const Descriptor& descriptor) const {
+ for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+ FixForeignFieldsInDescriptor(*descriptor.nested_type(i));
+ }
+
+ for (int i = 0; i < descriptor.field_count(); ++i) {
+ const FieldDescriptor& field_descriptor = *descriptor.field(i);
+ FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name");
+ }
+}
+
+// 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 string& python_dict_name) const {
+ const string field_referencing_expression = FieldReferencingExpression(
+ containing_type, field, python_dict_name);
+ map<string, 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.
+string Generator::FieldReferencingExpression(
+ const Descriptor* containing_type,
+ const FieldDescriptor& field,
+ const 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 field.name();
+ }
+ return strings::Substitute(
+ "$0.$1['$2']",
+ ModuleLevelDescriptorName(*containing_type),
+ python_dict_name, field.name());
+}
+
+// Prints statements setting the message_type and enum_type fields in the
+// Python descriptor objects we've already output in ths 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));
+ }
+ 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));
+ }
+}
+
+void Generator::FixForeignFieldsInExtension(
+ const FieldDescriptor& extension_field) const {
+ GOOGLE_CHECK(extension_field.is_extension());
+ // extension_scope() will be NULL for top-level extensions, which is
+ // exactly what FixForeignFieldsInField() wants.
+ FixForeignFieldsInField(extension_field.extension_scope(), extension_field,
+ "extensions_by_name");
+
+ map<string, 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::
+ string options_string;
+ descriptor.options().SerializeToString(&options_string);
+ map<string, string> m;
+ m["name"] = descriptor.name();
+ m["index"] = SimpleItoa(descriptor.index());
+ m["number"] = SimpleItoa(descriptor.number());
+ m["options"] = OptionsValue("EnumValueOptions", options_string);
+ printer_->Print(
+ m,
+ "descriptor.EnumValueDescriptor(\n"
+ " name='$name$', index=$index$, number=$number$,\n"
+ " options=$options$,\n"
+ " type=None)");
+}
+
+string Generator::OptionsValue(
+ const string& class_name, const string& serialized_options) const {
+ if (serialized_options.length() == 0 || GeneratingDescriptorProto()) {
+ return "None";
+ } else {
+ string full_class_name = "descriptor_pb2." + class_name;
+ return "descriptor._ParseOptions(" + full_class_name + "(), '"
+ + CEscape(serialized_options)+ "')";
+ }
+}
+
+// Prints an expression for a Python FieldDescriptor for |field|.
+void Generator::PrintFieldDescriptor(
+ const FieldDescriptor& field, bool is_extension) const {
+ string options_string;
+ field.options().SerializeToString(&options_string);
+ map<string, string> m;
+ m["name"] = field.name();
+ m["full_name"] = field.full_name();
+ m["index"] = SimpleItoa(field.index());
+ m["number"] = SimpleItoa(field.number());
+ m["type"] = SimpleItoa(field.type());
+ m["cpp_type"] = SimpleItoa(field.cpp_type());
+ m["label"] = SimpleItoa(field.label());
+ m["default_value"] = StringifyDefaultValue(field);
+ m["is_extension"] = is_extension ? "True" : "False";
+ m["options"] = OptionsValue("FieldOptions", options_string);
+ // 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"
+ " default_value=$default_value$,\n"
+ " message_type=None, enum_type=None, containing_type=None,\n"
+ " is_extension=$is_extension$, extension_scope=None,\n"
+ " options=$options$)";
+ printer_->Print(m, field_descriptor_decl);
+}
+
+// Helper for Print{Fields,Extensions}InDescriptor().
+void Generator::PrintFieldDescriptorsInDescriptor(
+ const Descriptor& message_descriptor,
+ bool is_extension,
+ const 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() == "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>
+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...
+ string name = NamePrefixedWithNestedTypes(descriptor, "_");
+ UpperString(&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 = ModuleName(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.
+string Generator::ModuleLevelMessageName(const Descriptor& descriptor) const {
+ string name = NamePrefixedWithNestedTypes(descriptor, ".");
+ if (descriptor.file() != file_) {
+ name = ModuleName(descriptor.file()->name()) + "." + name;
+ }
+ return name;
+}
+
+// Returns the unique Python module-level identifier given to a service
+// descriptor.
+string Generator::ModuleLevelServiceDescriptorName(
+ const ServiceDescriptor& descriptor) const {
+ string name = descriptor.name();
+ UpperString(&name);
+ name = "_" + name;
+ if (descriptor.file() != file_) {
+ name = ModuleName(descriptor.file()->name()) + "." + name;
+ }
+ return name;
+}
+
+} // namespace python
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
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 00000000..98ee0c6d
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -0,0 +1,129 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/compiler/code_generator.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class FieldDescriptor;
+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 LIBPROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+ Generator();
+ virtual ~Generator();
+
+ // CodeGenerator methods.
+ virtual bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ OutputDirectory* output_directory,
+ string* error) const;
+
+ private:
+ void PrintImports() const;
+ void PrintTopLevelEnums() const;
+ void PrintAllNestedEnumsInFile() const;
+ void PrintNestedEnums(const Descriptor& descriptor) const;
+ void PrintEnum(const EnumDescriptor& enum_descriptor) const;
+
+ void PrintTopLevelExtensions() const;
+
+ void PrintFieldDescriptor(
+ const FieldDescriptor& field, bool is_extension) const;
+ void PrintFieldDescriptorsInDescriptor(
+ const Descriptor& message_descriptor,
+ bool is_extension,
+ const 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;
+ void PrintNestedMessages(const Descriptor& containing_descriptor) const;
+
+ void FixForeignFieldsInDescriptors() const;
+ void FixForeignFieldsInDescriptor(const Descriptor& descriptor) const;
+ void FixForeignFieldsInField(const Descriptor* containing_type,
+ const FieldDescriptor& field,
+ const string& python_dict_name) const;
+ string FieldReferencingExpression(const Descriptor* containing_type,
+ const FieldDescriptor& field,
+ const string& python_dict_name) const;
+
+ void FixForeignFieldsInExtensions() const;
+ void FixForeignFieldsInExtension(
+ const FieldDescriptor& extension_field) const;
+ void FixForeignFieldsInNestedExtensions(const Descriptor& descriptor) const;
+
+ void PrintServices() const;
+ void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const;
+ void PrintServiceClass(const ServiceDescriptor& descriptor) const;
+ void PrintServiceStub(const ServiceDescriptor& descriptor) const;
+
+ void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const;
+ string OptionsValue(const string& class_name,
+ const string& serialized_options) const;
+ bool GeneratingDescriptorProto() const;
+
+ template <typename DescriptorT>
+ string ModuleLevelDescriptorName(const DescriptorT& descriptor) const;
+ string ModuleLevelMessageName(const Descriptor& descriptor) const;
+ string ModuleLevelServiceDescriptorName(
+ const ServiceDescriptor& descriptor) 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(Generator);
+};
+
+} // namespace python
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
new file mode 100644
index 00000000..c75cf623
--- /dev/null
+++ b/src/google/protobuf/descriptor.cc
@@ -0,0 +1,2838 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <set>
+#include <algorithm>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/stl_util-inl.h>
+
+#undef PACKAGE // autoheader #defines this. :(
+
+namespace google {
+namespace protobuf {
+
+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::kLabelToName[MAX_LABEL + 1] = {
+ "ERROR", // 0 is reserved for errors
+
+ "optional", // LABEL_OPTIONAL
+ "required", // LABEL_REQUIRED
+ "repeated", // LABEL_REPEATED
+};
+
+#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them.
+const int FieldDescriptor::kMaxNumber;
+const int FieldDescriptor::kFirstReservedNumber;
+const int FieldDescriptor::kLastReservedNumber;
+#endif
+
+namespace {
+
+const string kEmptyString;
+
+// 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. Unfortunately STL doesn't provide hash functions for pair<>,
+// so we must invent our own.
+//
+// TODO(kenton): Use StringPiece rather than const char* in keys? It would
+// be a lot cleaner but we'd just have to convert it back to const char*
+// for the open source release.
+
+typedef pair<const void*, const char*> PointerStringPair;
+
+// Used by GCC/SGI STL only. (Why isn't this provided by the standard
+// library? :( )
+struct CStringEqual {
+ inline bool operator()(const char* a, const char* b) const {
+ return strcmp(a, b) == 0;
+ }
+};
+
+struct PointerStringPairEqual {
+ inline bool operator()(const PointerStringPair& a,
+ const PointerStringPair& b) const {
+ return a.first == b.first && strcmp(a.second, b.second) == 0;
+ }
+};
+
+template<typename PairType>
+struct PointerIntegerPairHash {
+ size_t operator()(const PairType& p) const {
+ // FIXME(kenton): What is the best way to compute this hash? I have
+ // no idea! This seems a bit better than an XOR.
+ return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) + p.second;
+ }
+
+ // 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;
+ inline bool operator()(const PairType& a, const PairType& b) const {
+ return a.first < b.first ||
+ (a.first == b.first && a.second < b.second);
+ }
+};
+
+typedef pair<const Descriptor*, int> DescriptorIntPair;
+typedef pair<const EnumDescriptor*, int> EnumIntPair;
+
+struct PointerStringPairHash {
+ size_t operator()(const PointerStringPair& p) const {
+ // FIXME(kenton): What is the best way to compute this hash? I have
+ // no idea! This seems a bit better than an XOR.
+ hash<const char*> cstring_hash;
+ return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) +
+ cstring_hash(p.second);
+ }
+
+ // 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;
+ inline bool operator()(const PointerStringPair& a,
+ const PointerStringPair& b) const {
+ if (a.first < b.first) return true;
+ if (a.first > b.first) return false;
+ return strcmp(a.second, b.second) < 0;
+ }
+};
+
+
+struct Symbol {
+ enum Type {
+ NULL_SYMBOL, MESSAGE, FIELD, ENUM, ENUM_VALUE, SERVICE, METHOD, PACKAGE
+ };
+ Type type;
+ union {
+ const Descriptor* descriptor;
+ const FieldDescriptor* field_descriptor;
+ const EnumDescriptor* enum_descriptor;
+ const EnumValueDescriptor* enum_value_descriptor;
+ const ServiceDescriptor* service_descriptor;
+ const MethodDescriptor* method_descriptor;
+ const FileDescriptor* package_file_descriptor;
+ };
+
+ inline Symbol() : type(NULL_SYMBOL) { descriptor = NULL; }
+ inline bool IsNull() const { return type == NULL_SYMBOL; }
+
+#define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \
+ inline explicit Symbol(const TYPE* value) { \
+ type = TYPE_CONSTANT; \
+ this->FIELD = value; \
+ }
+
+ CONSTRUCTOR(Descriptor , MESSAGE , descriptor )
+ CONSTRUCTOR(FieldDescriptor , FIELD , field_descriptor )
+ CONSTRUCTOR(EnumDescriptor , ENUM , enum_descriptor )
+ CONSTRUCTOR(EnumValueDescriptor, ENUM_VALUE, enum_value_descriptor )
+ CONSTRUCTOR(ServiceDescriptor , SERVICE , service_descriptor )
+ CONSTRUCTOR(MethodDescriptor , METHOD , method_descriptor )
+ CONSTRUCTOR(FileDescriptor , PACKAGE , package_file_descriptor)
+#undef CONSTRUCTOR
+
+ const FileDescriptor* GetFile() const {
+ switch (type) {
+ case NULL_SYMBOL: return NULL;
+ case MESSAGE : return descriptor ->file();
+ case FIELD : return field_descriptor ->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 PACKAGE : return package_file_descriptor;
+ }
+ return NULL;
+ }
+};
+
+const Symbol kNullSymbol;
+
+typedef hash_map<const char*, Symbol,
+ hash<const char*>, CStringEqual>
+ SymbolsByNameMap;
+typedef hash_map<PointerStringPair, Symbol,
+ PointerStringPairHash, PointerStringPairEqual>
+ SymbolsByParentMap;
+typedef hash_map<const char*, const FileDescriptor*,
+ hash<const char*>, CStringEqual>
+ FilesByNameMap;
+typedef hash_map<DescriptorIntPair, const FieldDescriptor*,
+ PointerIntegerPairHash<DescriptorIntPair> >
+ FieldsByNumberMap;
+typedef hash_map<EnumIntPair, const EnumValueDescriptor*,
+ PointerIntegerPairHash<EnumIntPair> >
+ EnumValuesByNumberMap;
+
+} // anonymous namespace
+
+// ===================================================================
+// DescriptorPool::Tables
+
+class DescriptorPool::Tables {
+ public:
+ Tables();
+ ~Tables();
+
+ // Checkpoint the state of the tables. Future calls to Rollback() will
+ // return the Tables to this state. 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. BuildFile() calls
+ // Checkpoint() before it starts building and Rollback() if it encounters
+ // an error.
+ void Checkpoint();
+
+ // Roll back the Tables to the state of the last Checkpoint(), removing
+ // everything that was added after that point.
+ void Rollback();
+
+ // 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_ == NULL.
+ vector<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.
+ // Not used when fallback_database_ == NULL.
+ hash_set<string> known_bad_files_;
+
+ // -----------------------------------------------------------------
+ // Finding items.
+
+ // Find symbols. These return a null Symbol (symbol.IsNull() is true)
+ // if not found. FindSymbolOfType() additionally returns null if the
+ // symbol is not of the given type.
+ inline Symbol FindSymbol(const string& key) const;
+ inline Symbol FindSymbolOfType(const string& key,
+ const Symbol::Type type) const;
+ inline Symbol FindNestedSymbol(const void* parent,
+ const string& name) const;
+ inline Symbol FindNestedSymbolOfType(const void* parent,
+ const string& name,
+ const Symbol::Type type) const;
+
+ // These return NULL if not found.
+ inline const FileDescriptor* FindFile(const string& key) const;
+ inline const FieldDescriptor* FindFieldByNumber(
+ const Descriptor* parent, int number) const;
+ inline const EnumValueDescriptor* FindEnumValueByNumber(
+ 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. For AddSymbol(), the strings passed
+ // in must be ones that were constructed using AllocateString(), as they will
+ // be used as keys in the symbols_by_name_ and symbols_by_parent_ maps
+ // without copying. (If parent is NULL, nothing is added to
+ // symbols_by_parent_.)
+ bool AddSymbol(const string& full_name,
+ const void* parent, const string& name,
+ Symbol symbol);
+ bool AddFile(const FileDescriptor* file);
+ bool AddFieldByNumber(const FieldDescriptor* field);
+ bool AddEnumValueByNumber(const EnumValueDescriptor* value);
+
+ // Like AddSymbol(), but only adds to symbols_by_parent_, not
+ // symbols_by_name_. Used for enum values, which need to be registered
+ // under multiple parents (their type and its parent).
+ bool AddAliasUnderParent(const void* parent, const string& name,
+ Symbol symbol);
+
+ // -----------------------------------------------------------------
+ // 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 an array of objects which will be reclaimed when the
+ // pool in destroyed. Again, destructors are never called.
+ template<typename Type> Type* AllocateArray(int count);
+
+ // Allocate a string which will be destroyed when the pool is destroyed.
+ // The string is initialized to the given value for convenience.
+ string* AllocateString(const string& value);
+
+ // Allocate a protocol message object.
+ template<typename Type> Type* AllocateMessage();
+
+ private:
+ vector<string*> strings_; // All strings in the pool.
+ vector<Message*> messages_; // All messages in the pool.
+ vector<void*> allocations_; // All other memory allocated in the pool.
+
+ SymbolsByNameMap symbols_by_name_;
+ SymbolsByParentMap symbols_by_parent_;
+ FilesByNameMap files_by_name_;
+ FieldsByNumberMap fields_by_number_; // Includes extensions.
+ EnumValuesByNumberMap enum_values_by_number_;
+
+ int strings_before_checkpoint_;
+ int messages_before_checkpoint_;
+ int allocations_before_checkpoint_;
+ vector<const char* > symbols_after_checkpoint_;
+ vector<PointerStringPair> symbols_by_parent_after_checkpoint_;
+ vector<const char* > files_after_checkpoint_;
+ vector<DescriptorIntPair> field_numbers_after_checkpoint_;
+ vector<EnumIntPair > enum_numbers_after_checkpoint_;
+
+ // Allocate some bytes which will be reclaimed when the pool is
+ // destroyed.
+ void* AllocateBytes(int size);
+};
+
+DescriptorPool::Tables::Tables()
+ : strings_before_checkpoint_(0),
+ messages_before_checkpoint_(0),
+ allocations_before_checkpoint_(0) {}
+
+DescriptorPool::Tables::~Tables() {
+ for (int i = 0; i < allocations_.size(); i++) {
+ operator delete(allocations_[i]);
+ }
+ STLDeleteElements(&strings_);
+ STLDeleteElements(&messages_);
+}
+
+void DescriptorPool::Tables::Checkpoint() {
+ strings_before_checkpoint_ = strings_.size();
+ messages_before_checkpoint_ = messages_.size();
+ allocations_before_checkpoint_ = allocations_.size();
+
+ symbols_after_checkpoint_.clear();
+ symbols_by_parent_after_checkpoint_.clear();
+ files_after_checkpoint_.clear();
+ field_numbers_after_checkpoint_.clear();
+ enum_numbers_after_checkpoint_.clear();
+}
+
+void DescriptorPool::Tables::Rollback() {
+ for (int i = 0; i < symbols_after_checkpoint_.size(); i++) {
+ symbols_by_name_.erase(symbols_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < symbols_by_parent_after_checkpoint_.size(); i++) {
+ symbols_by_parent_.erase(symbols_by_parent_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < files_after_checkpoint_.size(); i++) {
+ files_by_name_.erase(files_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) {
+ fields_by_number_.erase(field_numbers_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < enum_numbers_after_checkpoint_.size(); i++) {
+ enum_values_by_number_.erase(enum_numbers_after_checkpoint_[i]);
+ }
+
+ symbols_after_checkpoint_.clear();
+ symbols_by_parent_after_checkpoint_.clear();
+ files_after_checkpoint_.clear();
+ field_numbers_after_checkpoint_.clear();
+ enum_numbers_after_checkpoint_.clear();
+
+ STLDeleteContainerPointers(
+ strings_.begin() + strings_before_checkpoint_, strings_.end());
+ STLDeleteContainerPointers(
+ messages_.begin() + messages_before_checkpoint_, messages_.end());
+ for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) {
+ operator delete(allocations_[i]);
+ }
+
+ strings_.resize(strings_before_checkpoint_);
+ messages_.resize(messages_before_checkpoint_);
+ allocations_.resize(allocations_before_checkpoint_);
+}
+
+// -------------------------------------------------------------------
+
+inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const {
+ const Symbol* result = FindOrNull(symbols_by_name_, key.c_str());
+ if (result == NULL) {
+ return kNullSymbol;
+ } else {
+ return *result;
+ }
+}
+
+inline Symbol DescriptorPool::Tables::FindSymbolOfType(
+ const string& key, const Symbol::Type type) const {
+ Symbol result = FindSymbol(key);
+ if (result.type != type) return kNullSymbol;
+ return result;
+}
+
+inline Symbol DescriptorPool::Tables::FindNestedSymbol(
+ const void* parent, const string& name) const {
+ const Symbol* result =
+ FindOrNull(symbols_by_parent_, PointerStringPair(parent, name.c_str()));
+ if (result == NULL) {
+ return kNullSymbol;
+ } else {
+ return *result;
+ }
+}
+
+inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType(
+ const void* parent, const string& name, const Symbol::Type type) const {
+ Symbol result = FindNestedSymbol(parent, name);
+ if (result.type != type) return kNullSymbol;
+ return result;
+}
+
+inline const FileDescriptor* DescriptorPool::Tables::FindFile(
+ const string& key) const {
+ return FindPtrOrNull(files_by_name_, key.c_str());
+}
+
+inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber(
+ const Descriptor* parent, int number) const {
+ return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
+}
+
+inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber(
+ const EnumDescriptor* parent, int number) const {
+ return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::Tables::AddSymbol(
+ const string& full_name,
+ const void* parent, const string& name,
+ Symbol symbol) {
+ if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) {
+ symbols_after_checkpoint_.push_back(full_name.c_str());
+
+ if (parent != NULL && !AddAliasUnderParent(parent, name, symbol)) {
+ 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 {
+ return false;
+ }
+}
+
+bool DescriptorPool::Tables::AddAliasUnderParent(
+ const void* parent, const string& name, Symbol symbol) {
+ PointerStringPair by_parent_key(parent, name.c_str());
+ if (InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol)) {
+ symbols_by_parent_after_checkpoint_.push_back(by_parent_key);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
+ if (InsertIfNotPresent(&files_by_name_, file->name().c_str(), file)) {
+ files_after_checkpoint_.push_back(file->name().c_str());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) {
+ DescriptorIntPair key(field->containing_type(), field->number());
+ if (InsertIfNotPresent(&fields_by_number_, key, field)) {
+ field_numbers_after_checkpoint_.push_back(key);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool DescriptorPool::Tables::AddEnumValueByNumber(
+ const EnumValueDescriptor* value) {
+ EnumIntPair key(value->type(), value->number());
+ if (InsertIfNotPresent(&enum_values_by_number_, key, value)) {
+ enum_numbers_after_checkpoint_.push_back(key);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// -------------------------------------------------------------------
+
+template<typename Type>
+Type* DescriptorPool::Tables::Allocate() {
+ return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type)));
+}
+
+template<typename Type>
+Type* DescriptorPool::Tables::AllocateArray(int count) {
+ return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type) * count));
+}
+
+string* DescriptorPool::Tables::AllocateString(const string& value) {
+ string* result = new string(value);
+ strings_.push_back(result);
+ return result;
+}
+
+template<typename Type>
+Type* DescriptorPool::Tables::AllocateMessage() {
+ Type* result = new Type;
+ messages_.push_back(result);
+ return result;
+}
+
+void* DescriptorPool::Tables::AllocateBytes(int size) {
+ // TODO(kenton): Would it be worthwhile to implement this in some more
+ // sophisticated way? Probably not for the open source release, but for
+ // internal use we could easily plug in one of our existing memory pool
+ // allocators...
+ if (size == 0) return NULL;
+
+ void* result = operator new(size);
+ allocations_.push_back(result);
+ return result;
+}
+
+// ===================================================================
+// DescriptorPool
+
+DescriptorPool::ErrorCollector::~ErrorCollector() {}
+
+DescriptorPool::DescriptorPool()
+ : mutex_(NULL),
+ fallback_database_(NULL),
+ default_error_collector_(NULL),
+ underlay_(NULL),
+ tables_(new Tables),
+ enforce_dependencies_(true),
+ last_internal_build_generated_file_call_(NULL) {}
+
+DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
+ ErrorCollector* error_collector)
+ : mutex_(new Mutex),
+ fallback_database_(fallback_database),
+ default_error_collector_(error_collector),
+ underlay_(NULL),
+ tables_(new Tables),
+ enforce_dependencies_(true),
+ last_internal_build_generated_file_call_(NULL) {
+}
+
+DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
+ : mutex_(NULL),
+ fallback_database_(NULL),
+ default_error_collector_(NULL),
+ underlay_(underlay),
+ tables_(new Tables),
+ last_internal_build_generated_file_call_(NULL) {}
+
+DescriptorPool::~DescriptorPool() {
+ if (mutex_ != NULL) delete mutex_;
+}
+
+// DescriptorPool::BuildFile() defined later.
+// DescriptorPool::BuildFileCollectingErrors() defined later.
+// DescriptorPool::InternalBuildGeneratedFile() defined later.
+
+const DescriptorPool* DescriptorPool::generated_pool() {
+ return internal_generated_pool();
+}
+
+DescriptorPool* DescriptorPool::internal_generated_pool() {
+ static DescriptorPool singleton;
+ return &singleton;
+}
+
+void DescriptorPool::InternalDontEnforceDependencies() {
+ enforce_dependencies_ = false;
+}
+
+// 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(const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ const FileDescriptor* result = tables_->FindFile(name);
+ if (result != NULL) return result;
+ if (underlay_ != NULL) {
+ const FileDescriptor* result = underlay_->FindFileByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindFileInFallbackDatabase(name)) {
+ const FileDescriptor* result = tables_->FindFile(name);
+ if (result != NULL) return result;
+ }
+ return NULL;
+}
+
+const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
+ const string& symbol_name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbol(symbol_name);
+ if (!result.IsNull()) return result.GetFile();
+ if (underlay_ != NULL) {
+ const FileDescriptor* result =
+ underlay_->FindFileContainingSymbol(symbol_name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(symbol_name)) {
+ Symbol result = tables_->FindSymbol(symbol_name);
+ if (!result.IsNull()) return result.GetFile();
+ }
+ return NULL;
+}
+
+const Descriptor* DescriptorPool::FindMessageTypeByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
+ if (!result.IsNull()) return result.descriptor;
+ if (underlay_ != NULL) {
+ const Descriptor* result = underlay_->FindMessageTypeByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
+ if (!result.IsNull()) return result.descriptor;
+ }
+ return NULL;
+}
+
+const FieldDescriptor* DescriptorPool::FindFieldByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
+ if (!result.IsNull() && !result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ }
+ if (underlay_ != NULL) {
+ const FieldDescriptor* result = underlay_->FindFieldByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
+ if (!result.IsNull() && !result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ }
+ }
+ return NULL;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
+ if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ }
+ if (underlay_ != NULL) {
+ const FieldDescriptor* result = underlay_->FindExtensionByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
+ if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ }
+ }
+ return NULL;
+}
+
+const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
+ if (!result.IsNull()) return result.enum_descriptor;
+ if (underlay_ != NULL) {
+ const EnumDescriptor* result = underlay_->FindEnumTypeByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
+ if (!result.IsNull()) return result.enum_descriptor;
+ }
+ return NULL;
+}
+
+const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
+ if (!result.IsNull()) return result.enum_value_descriptor;
+ if (underlay_ != NULL) {
+ const EnumValueDescriptor* result = underlay_->FindEnumValueByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
+ if (!result.IsNull()) return result.enum_value_descriptor;
+ }
+ return NULL;
+}
+
+const ServiceDescriptor* DescriptorPool::FindServiceByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
+ if (!result.IsNull()) return result.service_descriptor;
+ if (underlay_ != NULL) {
+ const ServiceDescriptor* result = underlay_->FindServiceByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
+ if (!result.IsNull()) return result.service_descriptor;
+ }
+ return NULL;
+}
+
+const MethodDescriptor* DescriptorPool::FindMethodByName(
+ const string& name) const {
+ MutexLockMaybe lock(mutex_);
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
+ if (!result.IsNull()) return result.method_descriptor;
+ if (underlay_ != NULL) {
+ const MethodDescriptor* result = underlay_->FindMethodByName(name);
+ if (result != NULL) return result;
+ }
+ if (TryFindSymbolInFallbackDatabase(name)) {
+ Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
+ if (!result.IsNull()) return result.method_descriptor;
+ }
+ return NULL;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
+ const Descriptor* extendee, int number) const {
+ MutexLockMaybe lock(mutex_);
+ const FieldDescriptor* result = tables_->FindFieldByNumber(extendee, number);
+ if (result != NULL && result->is_extension()) {
+ return result;
+ }
+ if (underlay_ != NULL) {
+ const FieldDescriptor* result =
+ underlay_->FindExtensionByNumber(extendee, number);
+ if (result != NULL) return result;
+ }
+ if (TryFindExtensionInFallbackDatabase(extendee, number)) {
+ const FieldDescriptor* result =
+ tables_->FindFieldByNumber(extendee, number);
+ if (result != NULL && result->is_extension()) {
+ return result;
+ }
+ }
+ return NULL;
+}
+
+// -------------------------------------------------------------------
+
+const FieldDescriptor*
+Descriptor::FindFieldByNumber(int key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByNumber(this, key);
+ if (result == NULL || result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindFieldByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
+ if (!result.IsNull() && !result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindExtensionByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
+ if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const Descriptor*
+Descriptor::FindNestedTypeByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
+ if (!result.IsNull()) {
+ return result.descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumDescriptor*
+Descriptor::FindEnumTypeByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
+ if (!result.IsNull()) {
+ return result.enum_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumValueDescriptor*
+Descriptor::FindEnumValueByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(
+ this, key, Symbol::ENUM_VALUE);
+ if (!result.IsNull()) {
+ return result.enum_value_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumValueDescriptor*
+EnumDescriptor::FindValueByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(
+ this, key, Symbol::ENUM_VALUE);
+ if (!result.IsNull()) {
+ return result.enum_value_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumValueDescriptor*
+EnumDescriptor::FindValueByNumber(int key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ return file()->pool()->tables_->FindEnumValueByNumber(this, key);
+}
+
+const MethodDescriptor*
+ServiceDescriptor::FindMethodByName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ Symbol result =
+ file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD);
+ if (!result.IsNull()) {
+ return result.method_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const Descriptor*
+FileDescriptor::FindMessageTypeByName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ Symbol result =
+ pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
+ if (!result.IsNull()) {
+ return result.descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumDescriptor*
+FileDescriptor::FindEnumTypeByName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ Symbol result =
+ pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
+ if (!result.IsNull()) {
+ return result.enum_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const EnumValueDescriptor*
+FileDescriptor::FindEnumValueByName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ Symbol result =
+ pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
+ if (!result.IsNull()) {
+ return result.enum_value_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const ServiceDescriptor*
+FileDescriptor::FindServiceByName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ Symbol result =
+ pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE);
+ if (!result.IsNull()) {
+ return result.service_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+const FieldDescriptor*
+FileDescriptor::FindExtensionByName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ Symbol result =
+ pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
+ if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ return result.field_descriptor;
+ } else {
+ return NULL;
+ }
+}
+
+bool Descriptor::IsExtensionNumber(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 true;
+ }
+ }
+ return false;
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
+ if (fallback_database_ == NULL) return false;
+
+ if (tables_->known_bad_files_.count(name) > 0) return false;
+
+ FileDescriptorProto file_proto;
+ if (!fallback_database_->FindFileByName(name, &file_proto) ||
+ BuildFileFromDatabase(file_proto) == NULL) {
+ tables_->known_bad_files_.insert(name);
+ return false;
+ }
+
+ return true;
+}
+
+bool DescriptorPool::TryFindSymbolInFallbackDatabase(const string& name) const {
+ if (fallback_database_ == NULL) return false;
+
+ FileDescriptorProto file_proto;
+ if (!fallback_database_->FindFileContainingSymbol(name, &file_proto)) {
+ return false;
+ }
+
+ if (tables_->FindFile(file_proto.name()) != NULL) {
+ // We've already loaded this file, and it apparently doesn't contain the
+ // symbol we're looking for. Some DescriptorDatabases return false
+ // positives.
+ return false;
+ }
+
+ if (BuildFileFromDatabase(file_proto) == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+bool DescriptorPool::TryFindExtensionInFallbackDatabase(
+ const Descriptor* containing_type, int field_number) const {
+ if (fallback_database_ == NULL) 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()) != NULL) {
+ // 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) == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+// ===================================================================
+
+string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const {
+ GOOGLE_CHECK(has_default_value()) << "No default value";
+ switch (cpp_type()) {
+ case CPPTYPE_INT32:
+ return SimpleItoa(default_value_int32());
+ break;
+ case CPPTYPE_INT64:
+ return SimpleItoa(default_value_int64());
+ break;
+ case CPPTYPE_UINT32:
+ return SimpleItoa(default_value_uint32());
+ break;
+ case CPPTYPE_UINT64:
+ return SimpleItoa(default_value_uint64());
+ break;
+ case CPPTYPE_FLOAT:
+ return SimpleFtoa(default_value_float());
+ break;
+ case CPPTYPE_DOUBLE:
+ return SimpleDtoa(default_value_double());
+ break;
+ case CPPTYPE_BOOL:
+ return default_value_bool() ? "true" : "false";
+ break;
+ 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();
+ }
+ }
+ break;
+ case CPPTYPE_ENUM:
+ return default_value_enum()->name();
+ break;
+ 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());
+
+ for (int i = 0; i < dependency_count(); i++) {
+ proto->add_dependency(dependency(i)->name());
+ }
+
+ 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 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 < 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++) {
+ DescriptorProto::ExtensionRange* range = proto->add_extension_range();
+ range->set_start(extension_range(i)->start);
+ range->set_end(extension_range(i)->end);
+ }
+ for (int i = 0; i < extension_count(); i++) {
+ extension(i)->CopyTo(proto->add_extension());
+ }
+
+ if (&options() != &MessageOptions::default_instance()) {
+ proto->mutable_options()->CopyFrom(options());
+ }
+}
+
+void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
+ proto->set_name(name());
+ proto->set_number(number());
+ proto->set_label(static_cast<FieldDescriptorProto::Label>(label()));
+ proto->set_type(static_cast<FieldDescriptorProto::Type>(type()));
+
+ if (is_extension()) {
+ proto->set_extendee(".");
+ proto->mutable_extendee()->append(containing_type()->full_name());
+ }
+
+ if (cpp_type() == CPPTYPE_MESSAGE) {
+ proto->set_type_name(".");
+ proto->mutable_type_name()->append(message_type()->full_name());
+ } else if (cpp_type() == CPPTYPE_ENUM) {
+ proto->set_type_name(".");
+ proto->mutable_type_name()->append(enum_type()->full_name());
+ }
+
+ if (has_default_value()) {
+ proto->set_default_value(DefaultValueAsString(false));
+ }
+
+ if (&options() != &FieldOptions::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());
+ }
+
+ 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());
+
+ proto->set_input_type(".");
+ proto->mutable_input_type()->append(input_type()->full_name());
+ proto->set_output_type(".");
+ proto->mutable_output_type()->append(output_type()->full_name());
+
+ if (&options() != &MethodOptions::default_instance()) {
+ proto->mutable_options()->CopyFrom(options());
+ }
+}
+
+// DebugString methods ===============================================
+
+namespace {
+
+// Used by each of the option formatters.
+bool RetrieveOptions(const Message &options, vector<string> *option_entries) {
+ option_entries->clear();
+ const Message::Reflection *reflection = options.GetReflection();
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ // Doesn't make sense to have message type fields here
+ if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ continue;
+ }
+ int count = 1;
+ bool repeated = false;
+ if (fields[i]->is_repeated()) {
+ count = reflection->FieldSize(fields[i]);
+ repeated = true;
+ }
+ for (int j = 0; j < count; j++) {
+ string fieldval;
+ TextFormat::PrintFieldValueToString(options, fields[i],
+ repeated ? count : -1, &fieldval);
+ option_entries->push_back(fields[i]->name() + " = " + fieldval);
+ }
+ }
+ return !option_entries->empty();
+}
+
+// Formats options that all appear together in brackets. Does not include
+// brackets.
+bool FormatBracketedOptions(const Message &options, string *output) {
+ vector<string> all_options;
+ if (RetrieveOptions(options, &all_options)) {
+ output->append(JoinStrings(all_options, ", "));
+ }
+ return !all_options.empty();
+}
+
+// Formats options one per line
+bool FormatLineOptions(int depth, const Message &options, string *output) {
+ string prefix(depth * 2, ' ');
+ vector<string> all_options;
+ if (RetrieveOptions(options, &all_options)) {
+ for (int i = 0; i < all_options.size(); i++) {
+ strings::SubstituteAndAppend(output, "$0option $1;\n",
+ prefix, all_options[i]);
+ }
+ }
+ return !all_options.empty();
+}
+
+} // anonymous namespace
+
+string FileDescriptor::DebugString() const {
+ string contents = "syntax = \"proto2\";\n\n";
+
+ for (int i = 0; i < dependency_count(); i++) {
+ strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
+ dependency(i)->name());
+ }
+
+ if (!package().empty()) {
+ strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+ }
+
+ if (FormatLineOptions(0, options(), &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);
+ 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).
+ 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) {
+ strings::SubstituteAndAppend(&contents, "message $0",
+ message_type(i)->name());
+ message_type(i)->DebugString(0, &contents);
+ contents.append("\n");
+ }
+ }
+
+ for (int i = 0; i < service_count(); i++) {
+ service(i)->DebugString(&contents);
+ contents.append("\n");
+ }
+
+ const Descriptor* containing_type = NULL;
+ 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);
+ }
+ if (extension_count() > 0) contents.append("}\n\n");
+
+ return contents;
+}
+
+string Descriptor::DebugString() const {
+ string contents;
+ strings::SubstituteAndAppend(&contents, "message $0", name());
+ DebugString(0, &contents);
+ return contents;
+}
+
+void Descriptor::DebugString(int depth, string *contents) const {
+ string prefix(depth * 2, ' ');
+ ++depth;
+ contents->append(" {\n");
+
+ FormatLineOptions(depth, options(), 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).
+ 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) {
+ strings::SubstituteAndAppend(contents, "$0 message $1",
+ prefix, nested_type(i)->name());
+ nested_type(i)->DebugString(depth, contents);
+ }
+ }
+ for (int i = 0; i < enum_type_count(); i++) {
+ enum_type(i)->DebugString(depth, contents);
+ }
+ for (int i = 0; i < field_count(); i++) {
+ field(i)->DebugString(depth, contents);
+ }
+
+ 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 = NULL;
+ 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);
+ }
+ if (extension_count() > 0)
+ strings::SubstituteAndAppend(contents, "$0 }\n", prefix);
+
+ strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+}
+
+string FieldDescriptor::DebugString() const {
+ string contents;
+ int depth = 0;
+ if (is_extension()) {
+ strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
+ containing_type()->full_name());
+ depth = 1;
+ }
+ DebugString(depth, &contents);
+ if (is_extension()) {
+ contents.append("}\n");
+ }
+ return contents;
+}
+
+void FieldDescriptor::DebugString(int depth, string *contents) const {
+ string prefix(depth * 2, ' ');
+ string field_type;
+ switch (type()) {
+ case TYPE_MESSAGE:
+ field_type = "." + message_type()->full_name();
+ break;
+ case TYPE_ENUM:
+ field_type = "." + enum_type()->full_name();
+ break;
+ default:
+ field_type = kTypeToName[type()];
+ }
+
+ strings::SubstituteAndAppend(contents, "$0$1 $2 $3 = $4",
+ prefix,
+ kLabelToName[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));
+ }
+
+ string formatted_options;
+ if (FormatBracketedOptions(options(), &formatted_options)) {
+ contents->append(bracketed ? ", " : " [");
+ bracketed = true;
+ contents->append(formatted_options);
+ }
+
+ if (bracketed) {
+ contents->append("]");
+ }
+
+ if (type() == TYPE_GROUP) {
+ message_type()->DebugString(depth, contents);
+ } else {
+ contents->append(";\n");
+ }
+}
+
+string EnumDescriptor::DebugString() const {
+ string contents;
+ DebugString(0, &contents);
+ return contents;
+}
+
+void EnumDescriptor::DebugString(int depth, string *contents) const {
+ string prefix(depth * 2, ' ');
+ ++depth;
+ strings::SubstituteAndAppend(contents, "$0enum $1 {\n",
+ prefix, name());
+
+ FormatLineOptions(depth, options(), contents);
+
+ for (int i = 0; i < value_count(); i++) {
+ value(i)->DebugString(depth, contents);
+ }
+ strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+}
+
+string EnumValueDescriptor::DebugString() const {
+ string contents;
+ DebugString(0, &contents);
+ return contents;
+}
+
+void EnumValueDescriptor::DebugString(int depth, string *contents) const {
+ string prefix(depth * 2, ' ');
+ strings::SubstituteAndAppend(contents, "$0$1 = $2",
+ prefix, name(), number());
+
+ string formatted_options;
+ if (FormatBracketedOptions(options(), &formatted_options)) {
+ strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
+ }
+ contents->append(";\n");
+}
+
+string ServiceDescriptor::DebugString() const {
+ string contents;
+ DebugString(&contents);
+ return contents;
+}
+
+void ServiceDescriptor::DebugString(string *contents) const {
+ strings::SubstituteAndAppend(contents, "service $0 {\n", name());
+
+ FormatLineOptions(1, options(), contents);
+
+ for (int i = 0; i < method_count(); i++) {
+ method(i)->DebugString(1, contents);
+ }
+
+ contents->append("}\n");
+}
+
+string MethodDescriptor::DebugString() const {
+ string contents;
+ DebugString(0, &contents);
+ return contents;
+}
+
+void MethodDescriptor::DebugString(int depth, string *contents) const {
+ string prefix(depth * 2, ' ');
+ ++depth;
+ strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)",
+ prefix, name(),
+ input_type()->full_name(),
+ output_type()->full_name());
+
+ string formatted_options;
+ if (FormatLineOptions(depth, options(), &formatted_options)) {
+ strings::SubstituteAndAppend(contents, " {\n$0$1}\n",
+ formatted_options, prefix);
+ } else {
+ contents->append(";\n");
+ }
+}
+// ===================================================================
+
+class DescriptorBuilder {
+ public:
+ DescriptorBuilder(const DescriptorPool* pool,
+ DescriptorPool::Tables* tables,
+ DescriptorPool::ErrorCollector* error_collector);
+ ~DescriptorBuilder();
+
+ const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
+
+ private:
+ const DescriptorPool* pool_;
+ DescriptorPool::Tables* tables_; // for convenience
+ DescriptorPool::ErrorCollector* error_collector_;
+ bool had_errors_;
+ string filename_;
+ FileDescriptor* file_;
+
+ // 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.
+ const FileDescriptor* possible_undeclared_dependency_;
+
+ void AddError(const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& error);
+
+ // Adds an error indicating that undefined_symbol was not defined. Must
+ // only be called after LookupSymbol() fails.
+ void AddNotDefinedError(
+ const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& undefined_symbol);
+
+ // 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 string& package_name);
+
+ // 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 string& name);
+
+ // Like FindSymbol(), but looks up the name relative to some other symbol
+ // name. This first searches syblings of relative_to, then siblings of its
+ // parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes
+ // the following calls, returning the first non-null result:
+ // FindSymbol("baz.qux.foo.bar"), FindSymbol("baz.foo.bar"),
+ // FindSymbol("foo.bar").
+ Symbol LookupSymbol(const string& name, const string& relative_to);
+
+ // Calls tables_->AddSymbol() and records an error if it fails.
+ void AddSymbol(const string& full_name,
+ const void* parent, const 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
+ // packgae to the symbol table (e.g. AddPackage("foo.bar", ...) will add
+ // "foo.bar" and "foo" to the table).
+ void AddPackage(const string& name, const Message& proto,
+ const FileDescriptor* file);
+
+ // Checks that the symbol name contains only alphanumeric characters and
+ // underscores. Records an error otherwise.
+ void ValidateSymbolName(const string& name, const string& full_name,
+ const Message& proto);
+
+ // Used by BUILD_ARRAY macro (below) to avoid having to have the type
+ // specified as a macro parameter.
+ template <typename Type>
+ inline void AllocateArray(int size, Type** output) {
+ *output = tables_->AllocateArray<Type>(size);
+ }
+
+ // 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);
+ void BuildFieldOrExtension(const FieldDescriptorProto& proto,
+ const Descriptor* parent,
+ FieldDescriptor* result,
+ bool is_extension);
+ void BuildField(const FieldDescriptorProto& proto,
+ const Descriptor* parent,
+ FieldDescriptor* result) {
+ BuildFieldOrExtension(proto, parent, result, false);
+ }
+ void BuildExtension(const FieldDescriptorProto& proto,
+ const Descriptor* parent,
+ FieldDescriptor* result) {
+ BuildFieldOrExtension(proto, parent, result, true);
+ }
+ void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
+ const Descriptor* parent,
+ Descriptor::ExtensionRange* result);
+ void BuildEnum(const EnumDescriptorProto& proto,
+ const Descriptor* parent,
+ EnumDescriptor* result);
+ void BuildEnumValue(const EnumValueDescriptorProto& proto,
+ const EnumDescriptor* parent,
+ EnumValueDescriptor* result);
+ void BuildService(const ServiceDescriptorProto& proto,
+ const void* dummy,
+ ServiceDescriptor* result);
+ void BuildMethod(const MethodDescriptorProto& proto,
+ const ServiceDescriptor* parent,
+ MethodDescriptor* result);
+
+ void CrossLinkFile(FileDescriptor* file, const FileDescriptorProto& proto);
+ void CrossLinkMessage(Descriptor* message, const DescriptorProto& proto);
+ void CrossLinkField(FieldDescriptor* field,
+ const FieldDescriptorProto& proto);
+ void CrossLinkService(ServiceDescriptor* service,
+ const ServiceDescriptorProto& proto);
+ void CrossLinkMethod(MethodDescriptor* method,
+ const MethodDescriptorProto& proto);
+ void CrossLinkMapKey(FieldDescriptor* field,
+ const FieldDescriptorProto& proto);
+};
+
+const FileDescriptor* DescriptorPool::BuildFile(
+ const FileDescriptorProto& proto) {
+ GOOGLE_CHECK(fallback_database_ == NULL)
+ << "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_ == NULL); // Implied by the above GOOGLE_CHECK.
+ return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
+ const FileDescriptorProto& proto,
+ ErrorCollector* error_collector) {
+ GOOGLE_CHECK(fallback_database_ == NULL)
+ << "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_ == NULL); // Implied by the above GOOGLE_CHECK.
+ return DescriptorBuilder(this, tables_.get(),
+ error_collector).BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileFromDatabase(
+ const FileDescriptorProto& proto) const {
+ mutex_->AssertHeld();
+ return DescriptorBuilder(this, tables_.get(),
+ default_error_collector_).BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::InternalBuildGeneratedFile(
+ const void* data, 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 BuildDescriptors() which is called the
+ // first time one of its descriptors is accessed, and that function calls
+ // this one in order to parse the raw bytes of the FileDescriptorProto
+ // representing the file.
+ //
+ // Note, though, that FileDescriptorProto is itself a generated protocol
+ // message. So, when we attempt to construct one below, it will attempt
+ // to initialize its own descriptors via its own BuildDescriptors() method.
+ // This will in turn cause InternalBuildGeneratedFile() to build
+ // descriptor.proto's descriptors.
+ //
+ // We are saved from an infinite loop by the fact that BuildDescriptors()
+ // only does anything the first time it is called. That is, the first few
+ // lines of any BuildDescriptors() procedure look like this:
+ // void BuildDescriptors() {
+ // static bool already_here = false;
+ // if (already_here) return;
+ // already_here = true;
+ // ...
+ // So, when descriptor.pb.cc's BuildDescriptors() is called recursively, it
+ // will end up just returning without doing anything. The result is that
+ // all of the descriptors for FileDescriptorProto and friends will just be
+ // NULL.
+ //
+ // Luckily, it turns out that our limited use of FileDescriptorProto within
+ // InternalBuildGeneratedFile() does not require that its descriptors be
+ // initialized. So, this ends up working. As soon as
+ // InternalBuildGeneratedFile() returns, the descriptors will be initialized
+ // by the original call to BuildDescriptors(), and everything will be happy
+ // again.
+ //
+ // If this turns out to be too fragile a hack, there are other ways we
+ // can accomplish bootstrapping here (like building the descriptor for
+ // descriptor.proto manually), but if this works then it's a lot easier.
+ //
+ // Note that because this is only triggered at static initialization time,
+ // there are no thread-safety concerns here.
+ FileDescriptorProto proto;
+ GOOGLE_CHECK(proto.ParseFromArray(data, size));
+ const FileDescriptor* result = BuildFile(proto);
+ GOOGLE_CHECK(result != NULL);
+
+ 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_(NULL) {}
+
+DescriptorBuilder::~DescriptorBuilder() {}
+
+void DescriptorBuilder::AddError(
+ const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& error) {
+ if (error_collector_ == NULL) {
+ 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::AddNotDefinedError(
+ const string& element_name,
+ const Message& descriptor,
+ DescriptorPool::ErrorCollector::ErrorLocation location,
+ const string& undefined_symbol) {
+ if (possible_undeclared_dependency_ == NULL) {
+ AddError(element_name, descriptor, location,
+ "\"" + undefined_symbol + "\" is not defined.");
+ } else {
+ AddError(element_name, descriptor, location,
+ "\"" + undefined_symbol + "\" seems to be defined in \""
+ + possible_undeclared_dependency_->name() + "\", which is not "
+ "imported by \"" + filename_ + "\". To use it here, please "
+ "add the necessary import.");
+ }
+}
+
+bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
+ const string& package_name) {
+ return HasPrefixString(file->package(), package_name) &&
+ (file->package().size() == package_name.size() ||
+ file->package()[package_name.size()] == '.');
+}
+
+Symbol DescriptorBuilder::FindSymbol(const string& name) {
+ Symbol result;
+
+ // We need to search our pool and all its underlays.
+ const DescriptorPool* pool = pool_;
+ while (true) {
+ // If we are looking at an underlay, we must lock its mutex_, since we are
+ // accessing the underlay's tables_ dircetly.
+ MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
+
+ // Note that we don't have to check fallback_database_ here because the
+ // symbol has to be in one of its file's direct dependencies, and we have
+ // already loaded those by the time we get here.
+ result = pool->tables_->FindSymbol(name);
+ if (!result.IsNull()) break;
+ if (pool->underlay_ == NULL) return kNullSymbol;
+ pool = pool->underlay_;
+ }
+
+ if (!pool_->enforce_dependencies_) {
+ // Hack for CompilerUpgrader.
+ return result;
+ }
+
+ // Only find symbols which were defined in this file or one of its
+ // dependencies.
+ const FileDescriptor* file = result.GetFile();
+ if (file == file_) return result;
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ if (file == file_->dependency(i)) return result;
+ }
+
+ if (result.type == Symbol::PACKAGE) {
+ // 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 (int i = 0; i < file_->dependency_count(); i++) {
+ if (IsInPackage(file_->dependency(i), name)) return result;
+ }
+ }
+
+ possible_undeclared_dependency_ = file;
+ return kNullSymbol;
+}
+
+Symbol DescriptorBuilder::LookupSymbol(
+ const string& name, const string& relative_to) {
+ possible_undeclared_dependency_ = NULL;
+
+ if (name.size() > 0 && name[0] == '.') {
+ // Fully-qualified name.
+ return FindSymbol(name.substr(1));
+ }
+
+ // 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.
+ int name_dot_pos = name.find_first_of('.');
+ string first_part_of_name;
+ if (name_dot_pos == string::npos) {
+ first_part_of_name = name;
+ } else {
+ first_part_of_name = name.substr(0, name_dot_pos);
+ }
+
+ string scope_to_try(relative_to);
+
+ while (true) {
+ // Chop off the last component of the scope.
+ string::size_type dot_pos = scope_to_try.find_last_of('.');
+ if (dot_pos == string::npos) {
+ return FindSymbol(name);
+ } else {
+ scope_to_try.erase(dot_pos);
+ }
+
+ // Append ".first_part_of_name" and try to find.
+ 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);
+ 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.
+ scope_to_try.append(name, first_part_of_name.size(),
+ name.size() - first_part_of_name.size());
+ result = FindSymbol(scope_to_try);
+ }
+ return result;
+ }
+
+ // Not found. Remove the name so we can try again.
+ scope_to_try.erase(old_size);
+ }
+}
+
+void DescriptorBuilder::AddSymbol(
+ const string& full_name, const void* parent, const string& name,
+ const Message& proto, Symbol symbol) {
+ // If the caller passed NULL for the parent, the symbol is at file scope.
+ // Use its file as the parent instead.
+ if (parent == NULL) parent = file_;
+
+ if (!tables_->AddSymbol(full_name, parent, name, symbol)) {
+ const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile();
+ if (other_file == file_) {
+ string::size_type dot_pos = full_name.find_last_of('.');
+ if (dot_pos == 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->name() + "\".");
+ }
+ }
+}
+
+void DescriptorBuilder::AddPackage(
+ const string& name, const Message& proto, const FileDescriptor* file) {
+ if (tables_->AddSymbol(name, NULL, name, Symbol(file))) {
+ // Success. Also add parent package, if any.
+ string::size_type dot_pos = name.find_last_of('.');
+ if (dot_pos == string::npos) {
+ // No parents.
+ ValidateSymbolName(name, name, proto);
+ } else {
+ // Has parent.
+ string* parent_name = tables_->AllocateString(name.substr(0, dot_pos));
+ AddPackage(*parent_name, proto, file);
+ ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
+ }
+ } else {
+ Symbol existing_symbol = tables_->FindSymbol(name);
+ // It's OK to redefine a package.
+ if (existing_symbol.type != Symbol::PACKAGE) {
+ // Symbol seems to have been defined in a different file.
+ AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+ "\"" + name + "\" is already defined (as something other than "
+ "a package) in file \"" + existing_symbol.GetFile()->name() +
+ "\".");
+ }
+ }
+}
+
+void DescriptorBuilder::ValidateSymbolName(
+ const string& name, const string& full_name, const Message& proto) {
+ if (name.empty()) {
+ AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+ "Missing name.");
+ } else {
+ for (int i = 0; i < name.size(); i++) {
+ // I don't trust isalnum() due to locales. :(
+ if ((name[i] < 'a' || 'z' < name[i]) &&
+ (name[i] < 'A' || 'Z' < name[i]) &&
+ (name[i] < '0' || '9' < name[i]) &&
+ (name[i] != '_')) {
+ AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+ "\"" + name + "\" is not a valid identifier.");
+ }
+ }
+ }
+}
+
+// -------------------------------------------------------------------
+
+// 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(); \
+ AllocateArray(INPUT.NAME##_size(), &OUTPUT->NAME##s_); \
+ for (int i = 0; i < INPUT.NAME##_size(); i++) { \
+ METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i); \
+ }
+
+const FileDescriptor* DescriptorBuilder::BuildFile(
+ const FileDescriptorProto& proto) {
+ filename_ = proto.name();
+
+ // 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 (int i = 0; i < tables_->pending_files_.size(); i++) {
+ if (tables_->pending_files_[i] == proto.name()) {
+ string error_message("File recursively imports itself: ");
+ for (; i < tables_->pending_files_.size(); i++) {
+ error_message.append(tables_->pending_files_[i]);
+ error_message.append(" -> ");
+ }
+ error_message.append(proto.name());
+
+ AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+ error_message);
+ return NULL;
+ }
+ }
+
+ // If we have a fallback_database_, attempt to load all dependencies now,
+ // before checkpointing tables_. This avoids confusion with recursive
+ // checkpoints.
+ if (pool_->fallback_database_ != NULL) {
+ tables_->pending_files_.push_back(proto.name());
+ for (int i = 0; i < proto.dependency_size(); i++) {
+ if (tables_->FindFile(proto.dependency(i)) == NULL &&
+ (pool_->underlay_ == NULL ||
+ pool_->underlay_->FindFileByName(proto.dependency(i)) == NULL)) {
+ // 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_->Checkpoint();
+
+ FileDescriptor* result = tables_->Allocate<FileDescriptor>();
+ file_ = result;
+
+ if (!proto.has_name()) {
+ AddError("", proto, DescriptorPool::ErrorCollector::OTHER,
+ "Missing field: FileDescriptorProto.name.");
+ }
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->package_ = tables_->AllocateString(proto.package());
+ result->pool_ = pool_;
+
+ // 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.
+ tables_->Rollback();
+ return NULL;
+ }
+ if (!result->package().empty()) {
+ AddPackage(result->package(), proto, result);
+ }
+
+ // Make sure all dependencies are loaded.
+ set<string> seen_dependencies;
+ result->dependency_count_ = proto.dependency_size();
+ result->dependencies_ =
+ tables_->AllocateArray<const FileDescriptor*>(proto.dependency_size());
+ for (int i = 0; i < proto.dependency_size(); i++) {
+ if (!seen_dependencies.insert(proto.dependency(i)).second) {
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Import \"" + proto.dependency(i) + "\" was listed twice.");
+ }
+
+ const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i));
+ if (dependency == NULL && pool_->underlay_ != NULL) {
+ dependency = pool_->underlay_->FindFileByName(proto.dependency(i));
+ }
+
+ if (dependency == NULL) {
+ string message;
+ if (pool_->fallback_database_ == NULL) {
+ message = "Import \"" + proto.dependency(i) +
+ "\" has not been loaded.";
+ } else {
+ message = "Import \"" + proto.dependency(i) +
+ "\" was not found or had errors.";
+ }
+ AddError(proto.name(), proto,
+ DescriptorPool::ErrorCollector::OTHER,
+ message);
+ }
+
+ result->dependencies_[i] = dependency;
+ }
+
+ // Convert children.
+ BUILD_ARRAY(proto, result, message_type, BuildMessage , NULL);
+ BUILD_ARRAY(proto, result, enum_type , BuildEnum , NULL);
+ BUILD_ARRAY(proto, result, service , BuildService , NULL);
+ BUILD_ARRAY(proto, result, extension , BuildExtension, NULL);
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &FileOptions::default_instance();
+ } else {
+ FileOptions* options = tables_->AllocateMessage<FileOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ // Cross-link.
+ CrossLinkFile(result, proto);
+
+ if (had_errors_) {
+ tables_->Rollback();
+ return NULL;
+ } else {
+ tables_->Checkpoint();
+ return result;
+ }
+}
+
+void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
+ const Descriptor* parent,
+ Descriptor* result) {
+ const string& scope = (parent == NULL) ?
+ file_->package() : parent->full_name();
+ string* full_name = tables_->AllocateString(scope);
+ if (!full_name->empty()) full_name->append(1, '.');
+ full_name->append(proto.name());
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->full_name_ = full_name;
+ result->file_ = file_;
+ result->containing_type_ = parent;
+
+ BUILD_ARRAY(proto, result, field , BuildField , result);
+ BUILD_ARRAY(proto, result, nested_type , BuildMessage , result);
+ BUILD_ARRAY(proto, result, enum_type , BuildEnum , result);
+ BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
+ BUILD_ARRAY(proto, result, extension , BuildExtension , result);
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &MessageOptions::default_instance();
+ } else {
+ MessageOptions* options = tables_->AllocateMessage<MessageOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ AddSymbol(result->full_name(), parent, result->name(),
+ proto, Symbol(result));
+
+ // Check that no fields have numbers in extension ranges.
+ 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) {
+ 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()));
+ }
+ }
+ }
+
+ // Check that extension ranges don't overlap.
+ for (int i = 0; i < result->extension_range_count(); i++) {
+ const Descriptor::ExtensionRange* range1 = result->extension_range(i);
+ 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(j),
+ 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,
+ const Descriptor* parent,
+ FieldDescriptor* result,
+ bool is_extension) {
+ const string& scope = (parent == NULL) ?
+ file_->package() : parent->full_name();
+ string* full_name = tables_->AllocateString(scope);
+ if (!full_name->empty()) full_name->append(1, '.');
+ full_name->append(proto.name());
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->full_name_ = full_name;
+ result->file_ = file_;
+ result->number_ = proto.number();
+ result->type_ = static_cast<FieldDescriptor::Type>(proto.type());
+ result->label_ = static_cast<FieldDescriptor::Label>(proto.label());
+ result->is_extension_ = is_extension;
+
+ // Some of these may be filled in when cross-linking.
+ result->containing_type_ = NULL;
+ result->extension_scope_ = NULL;
+ result->experimental_map_key_ = NULL;
+ result->message_type_ = NULL;
+ result->enum_type_ = NULL;
+
+ result->has_default_value_ = proto.has_default_value();
+ if (proto.has_type()) {
+ if (proto.has_default_value()) {
+ char* end_pos = NULL;
+ switch (result->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ result->default_value_int32_ =
+ strtol(proto.default_value().c_str(), &end_pos, 0);
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ result->default_value_int64_ =
+ strto64(proto.default_value().c_str(), &end_pos, 0);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ result->default_value_uint32_ =
+ strtoul(proto.default_value().c_str(), &end_pos, 0);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ result->default_value_uint64_ =
+ strtou64(proto.default_value().c_str(), &end_pos, 0);
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ result->default_value_float_ =
+ NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ result->default_value_double_ =
+ 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_ = NULL;
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (result->type() == FieldDescriptor::TYPE_BYTES) {
+ result->default_value_string_ = tables_->AllocateString(
+ UnescapeCEscapeString(proto.default_value()));
+ } else {
+ result->default_value_string_ =
+ tables_->AllocateString(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;
+ break;
+ }
+
+ if (end_pos != NULL) {
+ // 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.");
+ }
+ }
+ } else {
+ // No explicit default value
+ switch (result->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ result->default_value_int32_ = 0;
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ result->default_value_int64_ = 0;
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ result->default_value_uint32_ = 0;
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ result->default_value_uint64_ = 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_ = NULL;
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ result->default_value_string_ = &kEmptyString;
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ break;
+ }
+ }
+ }
+
+ if (result->number() <= 0) {
+ AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+ "Field numbers must be positive integers.");
+ } else if (result->number() > FieldDescriptor::kMaxNumber) {
+ 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) {
+ 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->extension_scope_ = parent;
+ } else {
+ if (proto.has_extendee()) {
+ AddError(result->full_name(), proto,
+ DescriptorPool::ErrorCollector::EXTENDEE,
+ "FieldDescriptorProto.extendee set for non-extension field.");
+ }
+
+ result->containing_type_ = parent;
+ }
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &FieldOptions::default_instance();
+ } else {
+ FieldOptions* options = tables_->AllocateMessage<FieldOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ AddSymbol(result->full_name(), parent, result->name(),
+ proto, Symbol(result));
+}
+
+void DescriptorBuilder::BuildExtensionRange(
+ const DescriptorProto::ExtensionRange& proto,
+ const Descriptor* parent,
+ Descriptor::ExtensionRange* result) {
+ result->start = proto.start();
+ result->end = proto.end();
+ if (result->start <= 0) {
+ AddError(parent->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER,
+ "Extension numbers must be positive integers.");
+ }
+
+ if (result->end > FieldDescriptor::kMaxNumber + 1) {
+ AddError(parent->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER,
+ strings::Substitute("Extension numbers cannot be greater than $0.",
+ FieldDescriptor::kMaxNumber));
+ }
+
+ if (result->start >= result->end) {
+ AddError(parent->full_name(), proto,
+ DescriptorPool::ErrorCollector::NUMBER,
+ "Extension range end number must be greater than start number.");
+ }
+}
+
+void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
+ const Descriptor* parent,
+ EnumDescriptor* result) {
+ const string& scope = (parent == NULL) ?
+ file_->package() : parent->full_name();
+ string* full_name = tables_->AllocateString(scope);
+ if (!full_name->empty()) full_name->append(1, '.');
+ full_name->append(proto.name());
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->full_name_ = full_name;
+ result->file_ = file_;
+ result->containing_type_ = parent;
+
+ 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.");
+ }
+
+ BUILD_ARRAY(proto, result, value, BuildEnumValue, result);
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &EnumOptions::default_instance();
+ } else {
+ EnumOptions* options = tables_->AllocateMessage<EnumOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ AddSymbol(result->full_name(), parent, result->name(),
+ proto, Symbol(result));
+}
+
+void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
+ const EnumDescriptor* parent,
+ EnumValueDescriptor* result) {
+ result->name_ = tables_->AllocateString(proto.name());
+ result->number_ = proto.number();
+ result->type_ = parent;
+
+ // Note: full_name for enum values is a sibling to the parent's name, not a
+ // child of it.
+ string* full_name = tables_->AllocateString(*parent->full_name_);
+ full_name->resize(full_name->size() - parent->name_->size());
+ full_name->append(*result->name_);
+ result->full_name_ = full_name;
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &EnumValueOptions::default_instance();
+ } else {
+ EnumValueOptions* options = tables_->AllocateMessage<EnumValueOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ // 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.
+ AddSymbol(result->full_name(), parent->containing_type(), result->name(),
+ proto, Symbol(result));
+
+ // 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.
+ tables_->AddAliasUnderParent(parent, result->name(), Symbol(result));
+
+ // 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.
+ tables_->AddEnumValueByNumber(result);
+}
+
+void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
+ const void* dummy,
+ ServiceDescriptor* result) {
+ string* full_name = tables_->AllocateString(file_->package());
+ if (!full_name->empty()) full_name->append(1, '.');
+ full_name->append(proto.name());
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ result->name_ = tables_->AllocateString(proto.name());
+ result->full_name_ = full_name;
+ result->file_ = file_;
+
+ BUILD_ARRAY(proto, result, method, BuildMethod, result);
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &ServiceOptions::default_instance();
+ } else {
+ ServiceOptions* options = tables_->AllocateMessage<ServiceOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ AddSymbol(result->full_name(), NULL, result->name(),
+ proto, Symbol(result));
+}
+
+void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
+ const ServiceDescriptor* parent,
+ MethodDescriptor* result) {
+ result->name_ = tables_->AllocateString(proto.name());
+ result->service_ = parent;
+
+ string* full_name = tables_->AllocateString(parent->full_name());
+ full_name->append(1, '.');
+ full_name->append(*result->name_);
+ result->full_name_ = full_name;
+
+ ValidateSymbolName(proto.name(), *full_name, proto);
+
+ // These will be filled in when cross-linking.
+ result->input_type_ = NULL;
+ result->output_type_ = NULL;
+
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = &MethodOptions::default_instance();
+ } else {
+ MethodOptions* options = tables_->AllocateMessage<MethodOptions>();
+ options->CopyFrom(proto.options());
+ result->options_ = options;
+ }
+
+ AddSymbol(result->full_name(), parent, result->name(),
+ proto, Symbol(result));
+}
+
+#undef BUILD_ARRAY
+
+// -------------------------------------------------------------------
+
+void DescriptorBuilder::CrossLinkFile(
+ FileDescriptor* file, const FileDescriptorProto& proto) {
+ 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->service_count(); i++) {
+ CrossLinkService(&file->services_[i], proto.service(i));
+ }
+}
+
+void DescriptorBuilder::CrossLinkMessage(
+ Descriptor* message, const DescriptorProto& proto) {
+ 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->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));
+ }
+}
+
+void DescriptorBuilder::CrossLinkField(
+ FieldDescriptor* field, const FieldDescriptorProto& proto) {
+ if (proto.has_extendee()) {
+ Symbol extendee = LookupSymbol(proto.extendee(), field->full_name());
+ 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;
+
+ if (!field->containing_type()->IsExtensionNumber(field->number())) {
+ 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 (proto.has_type_name()) {
+ Symbol type = LookupSymbol(proto.type_name(), field->full_name());
+ 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) {
+ if (type.type != Symbol::MESSAGE) {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "\"" + proto.type_name() + "\" is not a message type.");
+ return;
+ }
+ field->message_type_ = type.descriptor;
+
+ 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) {
+ if (type.type != Symbol::ENUM) {
+ AddError(field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "\"" + proto.type_name() + "\" is not an enum type.");
+ return;
+ }
+ field->enum_type_ = type.enum_descriptor;
+
+ if (field->has_default_value()) {
+ // 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.
+ Symbol default_value =
+ LookupSymbol(proto.default_value(), field->enum_type()->full_name());
+
+ if (default_value.type == Symbol::ENUM_VALUE &&
+ default_value.enum_value_descriptor->type() == field->enum_type()) {
+ field->default_value_enum_ = default_value.enum_value_descriptor;
+ } 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.");
+ }
+ }
+
+ if (proto.has_options() && proto.options().has_experimental_map_key()) {
+ CrossLinkMapKey(field, proto);
+ }
+
+ // 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 (!tables_->AddFieldByNumber(field)) {
+ const FieldDescriptor* conflicting_field =
+ tables_->FindFieldByNumber(field->containing_type(), field->number());
+ 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(),
+ field->containing_type()->full_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(),
+ field->containing_type()->full_name(),
+ conflicting_field->name()));
+ }
+ }
+
+ // Note: Default instance may not yet be initialized here, so we have to
+ // avoid reading from it.
+ if (field->containing_type_ != NULL &&
+ &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.");
+ }
+ }
+}
+
+void DescriptorBuilder::CrossLinkService(
+ ServiceDescriptor* service, const ServiceDescriptorProto& proto) {
+ for (int i = 0; i < service->method_count(); i++) {
+ CrossLinkMethod(&service->methods_[i], proto.method(i));
+ }
+}
+
+void DescriptorBuilder::CrossLinkMethod(
+ MethodDescriptor* method, const MethodDescriptorProto& proto) {
+ Symbol input_type = LookupSymbol(proto.input_type(), method->full_name());
+ if (input_type.IsNull()) {
+ AddNotDefinedError(method->full_name(), proto,
+ DescriptorPool::ErrorCollector::INPUT_TYPE,
+ proto.input_type());
+ } 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_ = input_type.descriptor;
+ }
+
+ Symbol output_type = LookupSymbol(proto.output_type(), method->full_name());
+ if (output_type.IsNull()) {
+ AddNotDefinedError(method->full_name(), proto,
+ DescriptorPool::ErrorCollector::OUTPUT_TYPE,
+ proto.output_type());
+ } 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_ = output_type.descriptor;
+ }
+}
+
+void DescriptorBuilder::CrossLinkMapKey(
+ FieldDescriptor* field,
+ const FieldDescriptorProto& proto) {
+ if (!field->is_repeated()) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "map type is only allowed for repeated fields.");
+ return;
+ }
+
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "map type is only allowed for fields with a message type.");
+ return;
+ }
+
+ const Descriptor* item_type = field->message_type();
+ if (item_type == NULL) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "Could not find field type.");
+ return;
+ }
+
+ // Find the field in item_type named by "experimental_map_key"
+ const string& key_name = proto.options().experimental_map_key();
+ const Symbol key_symbol = LookupSymbol(
+ key_name,
+ // We append ".key_name" to the containing type's name since
+ // LookupSymbol() searches for peers of the supplied name, not
+ // children of the supplied name.
+ item_type->full_name() + "." + key_name);
+
+ if (key_symbol.IsNull() || key_symbol.field_descriptor->is_extension()) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "Could not find field named \"" + key_name + "\" in type \"" +
+ item_type->full_name() + "\".");
+ return;
+ }
+ const FieldDescriptor* key_field = key_symbol.field_descriptor;
+
+ if (key_field->is_repeated()) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "map_key must not name a repeated field.");
+ return;
+ }
+
+ if (key_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+ "map key must name a scalar or string field.");
+ return;
+ }
+
+ field->experimental_map_key_ = key_field;
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
new file mode 100644
index 00000000..2bba4c38
--- /dev/null
+++ b/src/google/protobuf/descriptor.h
@@ -0,0 +1,1173 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/stubs/common.h>
+
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Descriptor;
+class FieldDescriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class ServiceDescriptor;
+class MethodDescriptor;
+class FileDescriptor;
+class DescriptorDatabase;
+class DescriptorPool;
+
+// Defined in descriptor.proto
+class DescriptorProto;
+class FieldDescriptorProto;
+class EnumDescriptorProto;
+class EnumValueDescriptorProto;
+class ServiceDescriptorProto;
+class MethodDescriptorProto;
+class FileDescriptorProto;
+class MessageOptions;
+class FieldOptions;
+class EnumOptions;
+class EnumValueOptions;
+class ServiceOptions;
+class MethodOptions;
+class FileOptions;
+
+// Defined in message.h
+class Message;
+
+// Defined in descriptor.cc
+class DescriptorBuilder;
+
+// 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 LIBPROTOBUF_EXPORT Descriptor {
+ public:
+ // The name of the message type, not including its scope.
+ const 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 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 NULL.
+ const FileDescriptor* file() const;
+
+ // If this Descriptor describes a nested type, this returns the type
+ // in which it is nested. Otherwise, returns NULL.
+ 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.
+ // The exact set of known options is defined by MessageOptions in
+ // google/protobuf/descriptor.proto.
+ 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 decriptor in a human-readable form. Output
+ // will be suitable for re-parsing.
+ string DebugString() 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().
+ const FieldDescriptor* field(int index) const;
+
+ // Looks up a field by declared tag number. Returns NULL if no such field
+ // exists.
+ const FieldDescriptor* FindFieldByNumber(int number) const;
+ // Looks up a field by name. Returns NULL if no such field exists.
+ const FieldDescriptor* FindFieldByName(const string& 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().
+ const Descriptor* nested_type(int index) const;
+
+ // Looks up a nested type by name. Returns NULL if no such nested type
+ // exists.
+ const Descriptor* FindNestedTypeByName(const string& 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().
+ const EnumDescriptor* enum_type(int index) const;
+
+ // Looks up an enum type by name. Returns NULL if no such enum type exists.
+ const EnumDescriptor* FindEnumTypeByName(const string& name) const;
+
+ // Looks up an enum value by name, among all enum types in this message.
+ // Returns NULL if no such value exists.
+ const EnumValueDescriptor* FindEnumValueByName(const string& name) const;
+
+ // Extensions ------------------------------------------------------
+
+ // A range of field numbers which are designated for third-party
+ // extensions.
+ struct ExtensionRange {
+ int start; // inclusive
+ int end; // exclusive
+ };
+
+ // 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().
+ const ExtensionRange* extension_range(int index) const;
+
+ // Returns true if the number is in one of the extension ranges.
+ bool IsExtensionNumber(int number) const;
+
+ // The number of extensions -- extending *other* messages -- that were
+ // defined nested within this message type's scope.
+ int extension_count() const;
+ // Get an extension by index, where 0 <= index < extension_count().
+ 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(const string& name) const;
+
+ private:
+ // Internal version of DebugString; controls the level of indenting for
+ // correct depth
+ void DebugString(int depth, string *contents) const;
+
+ const string* name_;
+ const string* full_name_;
+ const FileDescriptor* file_;
+ const Descriptor* containing_type_;
+ const MessageOptions* options_;
+ int field_count_;
+ FieldDescriptor* fields_;
+ int nested_type_count_;
+ Descriptor* nested_types_;
+ int enum_type_count_;
+ EnumDescriptor* enum_types_;
+ int extension_range_count_;
+ ExtensionRange* extension_ranges_;
+ int extension_count_;
+ FieldDescriptor* extensions_;
+
+ // Must be constructed using DescriptorPool.
+ Descriptor() {}
+ friend class DescriptorBuilder;
+ friend class EnumDescriptor;
+ friend class FieldDescriptor;
+ friend class FileDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor);
+};
+
+// 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().
+// - Given a Message::Reflection for a message object, call
+// Message::Reflection::FindKnownExtensionByName() or
+// Message::Reflection::FindKnownExtensionByNumber().
+// Use DescriptorPool to construct your own descriptors.
+class LIBPROTOBUF_EXPORT FieldDescriptor {
+ public:
+ // 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 string& name() const; // Name of this field within the message.
+ const string& full_name() const; // Fully-qualified name of the 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.
+
+ Type type() const; // Declared type of this field.
+ CppType cpp_type() const; // C++ type of this field.
+ 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
+
+ // 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;
+
+ // Get the field default value if cpp_type() == CPPTYPE_INT32. If no
+ // explicit default was defined, the default is 0.
+ int32 default_value_int32() const;
+ // Get the field default value if cpp_type() == CPPTYPE_INT64. If no
+ // explicit default was defined, the default is 0.
+ int64 default_value_int64() const;
+ // Get the field default value if cpp_type() == CPPTYPE_UINT32. If no
+ // explicit default was defined, the default is 0.
+ uint32 default_value_uint32() const;
+ // Get the field default value if cpp_type() == CPPTYPE_UINT64. If no
+ // explicit default was defined, the default is 0.
+ uint64 default_value_uint64() const;
+ // 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 NULL.
+ 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 string& default_value_string() const;
+
+ // The Descriptor for the message of which this is a field. For extensions,
+ // this is the extended type. Never NULL.
+ const Descriptor* containing_type() 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 NULL 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, undefined.
+ const Descriptor* message_type() const;
+ // If type is TYPE_ENUM, returns a descriptor for the enum. Otherwise,
+ // undefined.
+ const EnumDescriptor* enum_type() const;
+
+ // EXPERIMENTAL; DO NOT USE.
+ // If this field is a map field, experimental_map_key() is the field
+ // that is the key for this map.
+ // experimental_map_key()->containing_type() is the same as message_type().
+ const FieldDescriptor* experimental_map_key() const;
+
+ // Get the FieldOptions for this field. This includes things listed in
+ // square brackets after the field definition. E.g., the field:
+ // optional string text = 1 [ctype=CORD];
+ // has the "ctype" option set. FieldOptions is actually a protocol message,
+ // which makes it easier to extend.
+ const FieldOptions& options() const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(FieldDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+ private:
+ // See Descriptor::DebugString().
+ void DebugString(int depth, string *contents) const;
+
+ // formats the default value appropriately and returns it as a string.
+ // Must have a default value to call this. If quote_string_type is true, then
+ // types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped.
+ string DefaultValueAsString(bool quote_string_type) const;
+
+ const string* name_;
+ const string* full_name_;
+ const FileDescriptor* file_;
+ int number_;
+ Type type_;
+ Label label_;
+ bool is_extension_;
+ const Descriptor* containing_type_;
+ const Descriptor* extension_scope_;
+ const Descriptor* message_type_;
+ const EnumDescriptor* enum_type_;
+ const FieldDescriptor* experimental_map_key_;
+ const FieldOptions* options_;
+
+ bool has_default_value_;
+ union {
+ int32 default_value_int32_;
+ int64 default_value_int64_;
+ uint32 default_value_uint32_;
+ uint64 default_value_uint64_;
+ float default_value_float_;
+ double default_value_double_;
+ bool default_value_bool_;
+
+ const EnumValueDescriptor* default_value_enum_;
+ const string* default_value_string_;
+ };
+
+ static const CppType kTypeToCppTypeMap[MAX_TYPE + 1];
+
+ static const char * const kTypeToName[MAX_TYPE + 1];
+
+ static const char * const kLabelToName[MAX_LABEL + 1];
+
+ // Must be constructed using DescriptorPool.
+ FieldDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class FileDescriptor;
+ friend class Descriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor);
+};
+
+// 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 LIBPROTOBUF_EXPORT EnumDescriptor {
+ public:
+ // The name of this enum type in the containing scope.
+ const string& name() const;
+
+ // The fully-qualified name of the enum type, scope delimited by periods.
+ const 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 NULL.
+ 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().
+ const EnumValueDescriptor* value(int index) const;
+
+ // Looks up a value by name. Returns NULL if no such value exists.
+ const EnumValueDescriptor* FindValueByName(const string& name) const;
+ // Looks up a value by number. Returns NULL 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, NULL.
+ 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.
+ // The exact set of known options is defined by EnumOptions in
+ // google/protobuf/descriptor.proto.
+ const EnumOptions& options() const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(EnumDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+
+ private:
+ // See Descriptor::DebugString().
+ void DebugString(int depth, string *contents) const;
+
+ const string* name_;
+ const string* full_name_;
+ const FileDescriptor* file_;
+ int value_count_;
+ EnumValueDescriptor* values_;
+ const Descriptor* containing_type_;
+ const EnumOptions* options_;
+
+ // Must be constructed using DescriptorPool.
+ EnumDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class Descriptor;
+ friend class EnumValueDescriptor;
+ friend class FileDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
+};
+
+// 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 LIBPROTOBUF_EXPORT EnumValueDescriptor {
+ public:
+ const 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 string& full_name() const;
+
+ // The type of this value. Never NULL.
+ 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.
+ // The exact set of known options is defined by EnumValueOptions in
+ // google/protobuf/descriptor.proto.
+ const EnumValueOptions& options() const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(EnumValueDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+
+ private:
+ // See Descriptor::DebugString().
+ void DebugString(int depth, string *contents) const;
+
+ const string* name_;
+ const string* full_name_;
+ int number_;
+ const EnumDescriptor* type_;
+ const EnumValueOptions* options_;
+
+ // Must be constructed using DescriptorPool.
+ EnumValueDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class EnumDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
+};
+
+// Describes an RPC service. To get the ServiceDescriptor for a service,
+// call Service::GetDescriptor(). Generated service classes also have a
+// static method called descriptor() which returns the type's
+// ServiceDescriptor. Use DescriptorPool to construct your own descriptors.
+class LIBPROTOBUF_EXPORT ServiceDescriptor {
+ public:
+ // The name of the service, not including its containing scope.
+ const string& name() const;
+ // The fully-qualified name of the service, scope delimited by periods.
+ const 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 NULL.
+ 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.
+ // The exact set of known options is defined by ServiceOptions in
+ // google/protobuf/descriptor.proto.
+ 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().
+ const MethodDescriptor* method(int index) const;
+
+ // Look up a MethodDescriptor by name.
+ const MethodDescriptor* FindMethodByName(const string& name) const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(ServiceDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+
+ private:
+ // See Descriptor::DebugString().
+ void DebugString(string *contents) const;
+
+ const string* name_;
+ const string* full_name_;
+ const FileDescriptor* file_;
+ const ServiceOptions* options_;
+ int method_count_;
+ MethodDescriptor* methods_;
+
+ // Must be constructed using DescriptorPool.
+ ServiceDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class FileDescriptor;
+ friend class MethodDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor);
+};
+
+// 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 LIBPROTOBUF_EXPORT MethodDescriptor {
+ public:
+ // Name of this method, not including containing scope.
+ const string& name() const;
+ // The fully-qualified name of the method, scope delimited by periods.
+ const string& full_name() const;
+ // Index within the service's Descriptor.
+ int index() const;
+
+ // Gets the service to which this method belongs. Never NULL.
+ 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;
+
+ // 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. The exact set of known options is defined by
+ // MethodOptions in google/protobuf/descriptor.proto.
+ const MethodOptions& options() const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(MethodDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+
+ private:
+ // See Descriptor::DebugString().
+ void DebugString(int depth, string *contents) const;
+
+ const string* name_;
+ const string* full_name_;
+ const ServiceDescriptor* service_;
+ const Descriptor* input_type_;
+ const Descriptor* output_type_;
+ const MethodOptions* options_;
+
+ // Must be constructed using DescriptorPool.
+ MethodDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class ServiceDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
+};
+
+// 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 LIBPROTOBUF_EXPORT FileDescriptor {
+ public:
+ // The filename, relative to the source tree.
+ // e.g. "google/protobuf/descriptor.proto"
+ const string& name() const;
+
+ // The package, e.g. "google.protobuf.compiler".
+ const string& package() const;
+
+ // The DescriptorPool in which this FileDescriptor and all its contents were
+ // allocated. Never NULL.
+ 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().
+ const FileDescriptor* 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().
+ 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().
+ 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().
+ 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().
+ 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. The exact set of known options is defined by
+ // FileOptions in google/protobuf/descriptor.proto.
+ const FileOptions& options() const;
+
+ // Find a top-level message type by name. Returns NULL if not found.
+ const Descriptor* FindMessageTypeByName(const string& name) const;
+ // Find a top-level enum type by name. Returns NULL if not found.
+ const EnumDescriptor* FindEnumTypeByName(const string& name) const;
+ // Find an enum value defined in any top-level enum by name. Returns NULL if
+ // not found.
+ const EnumValueDescriptor* FindEnumValueByName(const string& name) const;
+ // Find a service definition by name. Returns NULL if not found.
+ const ServiceDescriptor* FindServiceByName(const string& name) const;
+ // Find a top-level extension definition by name. Returns NULL if not found.
+ const FieldDescriptor* FindExtensionByName(const string& name) const;
+
+ // See Descriptor::CopyTo().
+ void CopyTo(FileDescriptorProto* proto) const;
+
+ // See Descriptor::DebugString().
+ string DebugString() const;
+
+ private:
+ const string* name_;
+ const string* package_;
+ const DescriptorPool* pool_;
+ int dependency_count_;
+ const FileDescriptor** dependencies_;
+ int message_type_count_;
+ Descriptor* message_types_;
+ int enum_type_count_;
+ EnumDescriptor* enum_types_;
+ int service_count_;
+ ServiceDescriptor* services_;
+ int extension_count_;
+ FieldDescriptor* extensions_;
+ const FileOptions* options_;
+
+ FileDescriptor() {}
+ friend class DescriptorBuilder;
+ friend class Descriptor;
+ friend class FieldDescriptor;
+ friend class EnumDescriptor;
+ friend class ServiceDescriptor;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
+};
+
+// ===================================================================
+
+// 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 LIBPROTOBUF_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.
+ class ErrorCollector;
+ explicit DescriptorPool(DescriptorDatabase* fallback_database,
+ ErrorCollector* error_collector = NULL);
+
+ ~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 NULL if not
+ // found.
+ const FileDescriptor* FindFileByName(const string& 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 NULL.
+ const FileDescriptor* FindFileContainingSymbol(
+ const string& 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 NULL if not
+ // found.
+
+ const Descriptor* FindMessageTypeByName(const string& name) const;
+ const FieldDescriptor* FindFieldByName(const string& name) const;
+ const FieldDescriptor* FindExtensionByName(const string& name) const;
+ const EnumDescriptor* FindEnumTypeByName(const string& name) const;
+ const EnumValueDescriptor* FindEnumValueByName(const string& name) const;
+ const ServiceDescriptor* FindServiceByName(const string& name) const;
+ const MethodDescriptor* FindMethodByName(const string& 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;
+
+ // 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 LIBPROTOBUF_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
+ OTHER // some other problem
+ };
+
+ // Reports an error in the FileDescriptorProto.
+ virtual void AddError(
+ const string& filename, // File name in which the error occurred.
+ const string& element_name, // Full name of the erroneous element.
+ const Message* descriptor, // Descriptor of the erroneous element.
+ ErrorLocation location, // One of the location constants, above.
+ const string& message // Human-readable error message.
+ ) = 0;
+
+ 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 NULL 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);
+
+ // 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.
+
+ // DEPRECATED: Use of underlays can lead to many subtle gotchas. Instead,
+ // try to formulate what you want to do in terms of DescriptorDatabases.
+ // This constructor will be removed soon.
+ //
+ // 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.
+ explicit DescriptorPool(const DescriptorPool* underlay);
+
+ // Called by generated classes at init time. Do NOT call this in your
+ // own code!
+ const FileDescriptor* InternalBuildGeneratedFile(
+ const void* data, int size);
+
+ // 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 fallback database takes precedence.
+ static DescriptorPool* internal_generated_pool();
+
+ // 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.
+ void internal_set_underlay(const DescriptorPool* underlay) {
+ underlay_ = underlay;
+ }
+
+ private:
+ friend class Descriptor;
+ friend class FieldDescriptor;
+ friend class EnumDescriptor;
+ friend class ServiceDescriptor;
+ friend class FileDescriptor;
+ friend class DescriptorBuilder;
+
+ // 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(const string& name) const;
+ bool TryFindSymbolInFallbackDatabase(const string& name) const;
+ bool TryFindExtensionInFallbackDatabase(const Descriptor* containing_type,
+ int field_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;
+
+ // If fallback_database_ is NULL, this is NULL. Otherwise, this is a mutex
+ // which must be locked while accessing tables_.
+ Mutex* 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;
+ scoped_ptr<Tables> tables_;
+
+ bool enforce_dependencies_;
+
+ // See InternalBuildGeneratedFile().
+ const void* last_internal_build_generated_file_call_;
+
+ 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 string& CLASS::FIELD() const { return *FIELD##_; }
+
+// 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_STRING_ACCESSOR(Descriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, full_name)
+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, 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, 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_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
+
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, type, FieldDescriptor::Type)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, label, FieldDescriptor::Label)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, extension_scope, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key,
+ const FieldDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions);
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 )
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 )
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32, uint32)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64, uint64)
+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_ACCESSOR(FieldDescriptor, default_value_enum,
+ const EnumValueDescriptor*)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string)
+
+PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name)
+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_STRING_ACCESSOR(EnumValueDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions);
+
+PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name)
+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_STRING_ACCESSOR(MethodDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
+
+PROTOBUF_DEFINE_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, 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_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 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;
+}
+
+// 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 this - containing_type_->fields_;
+ } else if (extension_scope_ != NULL) {
+ return this - extension_scope_->extensions_;
+ } else {
+ return this - file_->extensions_;
+ }
+}
+
+inline int Descriptor::index() const {
+ if (containing_type_ == NULL) {
+ return this - file_->message_types_;
+ } else {
+ return this - containing_type_->nested_types_;
+ }
+}
+
+inline int EnumDescriptor::index() const {
+ if (containing_type_ == NULL) {
+ return this - file_->enum_types_;
+ } else {
+ return this - containing_type_->enum_types_;
+ }
+}
+
+inline int EnumValueDescriptor::index() const {
+ return this - type_->values_;
+}
+
+inline int ServiceDescriptor::index() const {
+ return this - file_->services_;
+}
+
+inline int MethodDescriptor::index() const {
+ return this - service_->methods_;
+}
+
+inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
+ return kTypeToCppTypeMap[type_];
+}
+
+inline const FileDescriptor* FileDescriptor::dependency(int index) const {
+ return dependencies_[index];
+}
+
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..836d141e
--- /dev/null
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -0,0 +1,3935 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format_inl.h>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* FileDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* DescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* FieldDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* EnumDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* EnumValueDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ServiceDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* MethodDescriptorProto_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* FileOptions_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* MessageOptions_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* FieldOptions_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* EnumValueOptions_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ServiceOptions_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* MethodOptions_descriptor_ = NULL;
+
+} // namespace
+
+
+void proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ ::google::protobuf::DescriptorPool* pool =
+ ::google::protobuf::DescriptorPool::internal_generated_pool();
+
+ const ::google::protobuf::FileDescriptor* file = pool->InternalBuildGeneratedFile(
+ "\n google/protobuf/descriptor.proto\022\017goog"
+ "le.protobuf\"\334\002\n\023FileDescriptorProto\022\014\n\004n"
+ "ame\030\001 \001(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency"
+ "\030\003 \003(\t\0226\n\014message_type\030\004 \003(\0132 .google.pr"
+ "otobuf.DescriptorProto\0227\n\tenum_type\030\005 \003("
+ "\0132$.google.protobuf.EnumDescriptorProto\022"
+ "8\n\007service\030\006 \003(\0132\'.google.protobuf.Servi"
+ "ceDescriptorProto\0228\n\textension\030\007 \003(\0132%.g"
+ "oogle.protobuf.FieldDescriptorProto\022-\n\007o"
+ "ptions\030\010 \001(\0132\034.google.protobuf.FileOptio"
+ "ns\"\251\003\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\0220\n\007options\030\007 \001(\0132\037.google"
+ ".protobuf.MessageOptions\032,\n\016ExtensionRan"
+ "ge\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\224\005\n\024Field"
+ "DescriptorProto\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.F"
+ "ieldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162"
+ "*.google.protobuf.FieldDescriptorProto.T"
+ "ype\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.\n\007options\030\010 \001(\013"
+ "2\035.google.protobuf.FieldOptions\"\266\002\n\004Type"
+ "\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYP"
+ "E_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32"
+ "\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r"
+ "\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_G"
+ "ROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014"
+ "\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE"
+ "_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_S"
+ "INT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LAB"
+ "EL_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LAB"
+ "EL_REPEATED\020\003\"\214\001\n\023EnumDescriptorProto\022\014\n"
+ "\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.prot"
+ "obuf.EnumValueDescriptorProto\022-\n\007options"
+ "\030\003 \001(\0132\034.google.protobuf.EnumOptions\"l\n\030"
+ "EnumValueDescriptorProto\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.EnumValueOptions\"\220\001\n\026ServiceDe"
+ "scriptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 "
+ "\003(\0132&.google.protobuf.MethodDescriptorPr"
+ "oto\0220\n\007options\030\003 \001(\0132\037.google.protobuf.S"
+ "erviceOptions\"\177\n\025MethodDescriptorProto\022\014"
+ "\n\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outp"
+ "ut_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google."
+ "protobuf.MethodOptions\"\333\001\n\013FileOptions\022\024"
+ "\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_class"
+ "name\030\010 \001(\t\022\"\n\023java_multiple_files\030\n \001(\010:"
+ "\005false\022J\n\014optimize_for\030\t \001(\0162).google.pr"
+ "otobuf.FileOptions.OptimizeMode:\tCODE_SI"
+ "ZE\"(\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SI"
+ "ZE\020\002\"8\n\016MessageOptions\022&\n\027message_set_wi"
+ "re_format\030\001 \001(\010:\005false\"\205\001\n\014FieldOptions\022"
+ "2\n\005ctype\030\001 \001(\0162#.google.protobuf.FieldOp"
+ "tions.CType\022\034\n\024experimental_map_key\030\t \001("
+ "\t\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"\r"
+ "\n\013EnumOptions\"\022\n\020EnumValueOptions\"\020\n\016Ser"
+ "viceOptions\"\017\n\rMethodOptionsB)\n\023com.goog"
+ "le.protobufB\020DescriptorProtosH\001", 2551);
+ FileDescriptorProto_descriptor_ = file->message_type(0);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance());
+ DescriptorProto_descriptor_ = file->message_type(1);
+ DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ DescriptorProto_descriptor_, &DescriptorProto::default_instance());
+ FieldDescriptorProto_descriptor_ = file->message_type(2);
+ FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0);
+ FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
+ EnumDescriptorProto_descriptor_ = file->message_type(3);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance());
+ EnumValueDescriptorProto_descriptor_ = file->message_type(4);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance());
+ ServiceDescriptorProto_descriptor_ = file->message_type(5);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance());
+ MethodDescriptorProto_descriptor_ = file->message_type(6);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance());
+ FileOptions_descriptor_ = file->message_type(7);
+ FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ FileOptions_descriptor_, &FileOptions::default_instance());
+ MessageOptions_descriptor_ = file->message_type(8);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ MessageOptions_descriptor_, &MessageOptions::default_instance());
+ FieldOptions_descriptor_ = file->message_type(9);
+ FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ FieldOptions_descriptor_, &FieldOptions::default_instance());
+ EnumOptions_descriptor_ = file->message_type(10);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ EnumOptions_descriptor_, &EnumOptions::default_instance());
+ EnumValueOptions_descriptor_ = file->message_type(11);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
+ ServiceOptions_descriptor_ = file->message_type(12);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ServiceOptions_descriptor_, &ServiceOptions::default_instance());
+ MethodOptions_descriptor_ = file->message_type(13);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ MethodOptions_descriptor_, &MethodOptions::default_instance());
+}
+
+// Force BuildDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto {
+ StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto() {
+ proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ }
+} static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_;
+
+
+// ===================================================================
+
+const FileDescriptorProto FileDescriptorProto::default_instance_;
+
+const ::std::string FileDescriptorProto::_default_name_;
+const ::std::string FileDescriptorProto::_default_package_;
+
+
+
+
+
+
+const int FileDescriptorProto::_offsets_[8] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, dependency_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, message_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, enum_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, service_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, extension_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, options_),
+};
+
+FileDescriptorProto::FileDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ package_(const_cast< ::std::string*>(&_default_package_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::FileOptions*>(&::google::protobuf::FileOptions::default_instance());
+ }
+}
+
+FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ package_(const_cast< ::std::string*>(&_default_package_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+FileDescriptorProto::~FileDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (package_ != &_default_package_) {
+ delete package_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() {
+ if (FileDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FileDescriptorProto_descriptor_;
+}
+
+FileDescriptorProto* FileDescriptorProto::New() const {
+ return new FileDescriptorProto;
+}
+
+void FileDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ if (_has_bit(1)) {
+ if (package_ != &_default_package_) {
+ package_->clear();
+ }
+ }
+ if (_has_bit(7)) {
+ if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
+ }
+ }
+ dependency_.Clear();
+ message_type_.Clear();
+ enum_type_.Clear();
+ service_.Clear();
+ extension_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool FileDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_package;
+ break;
+ }
+
+ // optional string package = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_package:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_package()));
+ if (input->ExpectTag(26)) goto parse_dependency;
+ break;
+ }
+
+ // repeated string dependency = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_dependency:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(
+ input, add_dependency()));
+ if (input->ExpectTag(26)) goto parse_dependency;
+ if (input->ExpectTag(34)) goto parse_message_type;
+ break;
+ }
+
+ // repeated .google.protobuf.DescriptorProto message_type = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_message_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_message_type()));
+ if (input->ExpectTag(34)) goto parse_message_type;
+ if (input->ExpectTag(42)) goto parse_enum_type;
+ break;
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+ case 5: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_enum_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_enum_type()));
+ if (input->ExpectTag(42)) goto parse_enum_type;
+ if (input->ExpectTag(50)) goto parse_service;
+ break;
+ }
+
+ // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+ case 6: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_service:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_service()));
+ if (input->ExpectTag(50)) goto parse_service;
+ if (input->ExpectTag(58)) goto parse_extension;
+ break;
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+ case 7: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_extension:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_extension()));
+ if (input->ExpectTag(58)) goto parse_extension;
+ if (input->ExpectTag(66)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.FileOptions options = 8;
+ case 8: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool FileDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // optional string package = 2;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->package(), output));
+ }
+
+ // repeated string dependency = 3;
+ for (int i = 0; i < dependency_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->dependency(i), output));
+ }
+
+ // repeated .google.protobuf.DescriptorProto message_type = 4;
+ for (int i = 0; i < message_type_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->message_type(i), output));
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+ for (int i = 0; i < enum_type_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->enum_type(i), output));
+ }
+
+ // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+ for (int i = 0; i < service_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->service(i), output));
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+ for (int i = 0; i < extension_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->extension(i), output));
+ }
+
+ // optional .google.protobuf.FileOptions options = 8;
+ if (_has_bit(7)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int FileDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional string package = 2;
+ if (has_package()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->package());
+ }
+
+ // optional .google.protobuf.FileOptions options = 8;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ // repeated string dependency = 3;
+ total_size += 1 * dependency_size();
+ for (int i = 0; i < dependency_size(); i++) {
+ total_size += ::google::protobuf::internal::WireFormat::StringSize(
+ this->dependency(i));
+ }
+
+ // repeated .google.protobuf.DescriptorProto message_type = 4;
+ total_size += 1 * message_type_size();
+ for (int i = 0; i < message_type_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->message_type(i));
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+ total_size += 1 * enum_type_size();
+ for (int i = 0; i < enum_type_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->enum_type(i));
+ }
+
+ // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+ total_size += 1 * service_size();
+ for (int i = 0; i < service_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->service(i));
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+ total_size += 1 * extension_size();
+ for (int i = 0; i < extension_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->extension(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const FileDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ dependency_.MergeFrom(from.dependency_);
+ message_type_.MergeFrom(from.message_type_);
+ enum_type_.MergeFrom(from.enum_type_);
+ service_.MergeFrom(from.service_);
+ extension_.MergeFrom(from.extension_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(1)) {
+ set_package(from.package());
+ }
+ if (from._has_bit(7)) {
+ mutable_options()->::google::protobuf::FileOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool FileDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* FileDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+FileDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* FileDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const DescriptorProto_ExtensionRange DescriptorProto_ExtensionRange::default_instance_;
+
+
+
+const int DescriptorProto_ExtensionRange::_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, end_),
+};
+
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ start_(0),
+ end_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ start_(0),
+ end_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() {
+ if (DescriptorProto_ExtensionRange_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return DescriptorProto_ExtensionRange_descriptor_;
+}
+
+DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New() const {
+ return new DescriptorProto_ExtensionRange;
+}
+
+void DescriptorProto_ExtensionRange::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ start_ = 0;
+ end_ = 0;
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional int32 start = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadInt32(
+ input, &start_));
+ _set_bit(0);
+ if (input->ExpectTag(16)) goto parse_end;
+ break;
+ }
+
+ // optional int32 end = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_end:
+ DO_(::google::protobuf::internal::WireFormat::ReadInt32(
+ input, &end_));
+ _set_bit(1);
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional int32 start = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteInt32(1, this->start(), output));
+ }
+
+ // optional int32 end = 2;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteInt32(2, this->end(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int DescriptorProto_ExtensionRange::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional int32 start = 1;
+ if (has_start()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::Int32Size(
+ this->start());
+ }
+
+ // optional int32 end = 2;
+ if (has_end()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::Int32Size(
+ this->end());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const DescriptorProto_ExtensionRange* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto_ExtensionRange*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_start(from.start());
+ }
+ if (from._has_bit(1)) {
+ set_end(from.end());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool DescriptorProto_ExtensionRange::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+DescriptorProto_ExtensionRange::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* DescriptorProto_ExtensionRange::GetReflection() {
+ return &_reflection_;
+}
+
+// -------------------------------------------------------------------
+
+const DescriptorProto DescriptorProto::default_instance_;
+
+const ::std::string DescriptorProto::_default_name_;
+
+
+
+
+
+
+const int DescriptorProto::_offsets_[7] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, nested_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, enum_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_),
+};
+
+DescriptorProto::DescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::MessageOptions*>(&::google::protobuf::MessageOptions::default_instance());
+ }
+}
+
+DescriptorProto::DescriptorProto(const DescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+DescriptorProto::~DescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* DescriptorProto::descriptor() {
+ if (DescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return DescriptorProto_descriptor_;
+}
+
+DescriptorProto* DescriptorProto::New() const {
+ return new DescriptorProto;
+}
+
+void DescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ if (_has_bit(6)) {
+ if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
+ }
+ }
+ field_.Clear();
+ extension_.Clear();
+ nested_type_.Clear();
+ enum_type_.Clear();
+ extension_range_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool DescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_field;
+ break;
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto field = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_field:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_field()));
+ if (input->ExpectTag(18)) goto parse_field;
+ if (input->ExpectTag(26)) goto parse_nested_type;
+ break;
+ }
+
+ // repeated .google.protobuf.DescriptorProto nested_type = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_nested_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_nested_type()));
+ if (input->ExpectTag(26)) goto parse_nested_type;
+ if (input->ExpectTag(34)) goto parse_enum_type;
+ break;
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_enum_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_enum_type()));
+ if (input->ExpectTag(34)) goto parse_enum_type;
+ if (input->ExpectTag(42)) goto parse_extension_range;
+ break;
+ }
+
+ // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+ case 5: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_extension_range:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_extension_range()));
+ if (input->ExpectTag(42)) goto parse_extension_range;
+ if (input->ExpectTag(50)) goto parse_extension;
+ break;
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+ case 6: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_extension:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_extension()));
+ if (input->ExpectTag(50)) goto parse_extension;
+ if (input->ExpectTag(58)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.MessageOptions options = 7;
+ case 7: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool DescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto field = 2;
+ for (int i = 0; i < field_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->field(i), output));
+ }
+
+ // repeated .google.protobuf.DescriptorProto nested_type = 3;
+ for (int i = 0; i < nested_type_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->nested_type(i), output));
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+ for (int i = 0; i < enum_type_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->enum_type(i), output));
+ }
+
+ // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+ for (int i = 0; i < extension_range_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->extension_range(i), output));
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+ for (int i = 0; i < extension_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->extension(i), output));
+ }
+
+ // optional .google.protobuf.MessageOptions options = 7;
+ if (_has_bit(6)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int DescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional .google.protobuf.MessageOptions options = 7;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ // repeated .google.protobuf.FieldDescriptorProto field = 2;
+ total_size += 1 * field_size();
+ for (int i = 0; i < field_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->field(i));
+ }
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+ total_size += 1 * extension_size();
+ for (int i = 0; i < extension_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->extension(i));
+ }
+
+ // repeated .google.protobuf.DescriptorProto nested_type = 3;
+ total_size += 1 * nested_type_size();
+ for (int i = 0; i < nested_type_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->nested_type(i));
+ }
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+ total_size += 1 * enum_type_size();
+ for (int i = 0; i < enum_type_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->enum_type(i));
+ }
+
+ // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+ total_size += 1 * extension_range_size();
+ for (int i = 0; i < extension_range_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->extension_range(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const DescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void DescriptorProto::MergeFrom(const DescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ field_.MergeFrom(from.field_);
+ extension_.MergeFrom(from.extension_);
+ nested_type_.MergeFrom(from.nested_type_);
+ enum_type_.MergeFrom(from.enum_type_);
+ extension_range_.MergeFrom(from.extension_range_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(6)) {
+ mutable_options()->::google::protobuf::MessageOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void DescriptorProto::CopyFrom(const DescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool DescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* DescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+DescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* DescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor() {
+ if (FieldDescriptorProto_Type_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FieldDescriptorProto_Type_descriptor_;
+}
+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;
+ }
+}
+
+#ifndef _MSC_VER
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32;
+const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
+const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
+const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
+#endif // _MSC_VER
+const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
+ if (FieldDescriptorProto_Label_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FieldDescriptorProto_Label_descriptor_;
+}
+bool FieldDescriptorProto_Label_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
+const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
+const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
+const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
+const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
+#endif // _MSC_VER
+const FieldDescriptorProto FieldDescriptorProto::default_instance_;
+
+const ::std::string FieldDescriptorProto::_default_name_;
+
+
+
+const ::std::string FieldDescriptorProto::_default_type_name_;
+const ::std::string FieldDescriptorProto::_default_extendee_;
+const ::std::string FieldDescriptorProto::_default_default_value_;
+
+const int FieldDescriptorProto::_offsets_[8] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, type_name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_),
+};
+
+FieldDescriptorProto::FieldDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ number_(0),
+ label_(1),
+ type_(1),
+ type_name_(const_cast< ::std::string*>(&_default_type_name_)),
+ extendee_(const_cast< ::std::string*>(&_default_extendee_)),
+ default_value_(const_cast< ::std::string*>(&_default_default_value_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::FieldOptions*>(&::google::protobuf::FieldOptions::default_instance());
+ }
+}
+
+FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ number_(0),
+ label_(1),
+ type_(1),
+ type_name_(const_cast< ::std::string*>(&_default_type_name_)),
+ extendee_(const_cast< ::std::string*>(&_default_extendee_)),
+ default_value_(const_cast< ::std::string*>(&_default_default_value_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+FieldDescriptorProto::~FieldDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (type_name_ != &_default_type_name_) {
+ delete type_name_;
+ }
+ if (extendee_ != &_default_extendee_) {
+ delete extendee_;
+ }
+ if (default_value_ != &_default_default_value_) {
+ delete default_value_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() {
+ if (FieldDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FieldDescriptorProto_descriptor_;
+}
+
+FieldDescriptorProto* FieldDescriptorProto::New() const {
+ return new FieldDescriptorProto;
+}
+
+void FieldDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ number_ = 0;
+ label_ = 1;
+ type_ = 1;
+ if (_has_bit(4)) {
+ if (type_name_ != &_default_type_name_) {
+ type_name_->clear();
+ }
+ }
+ if (_has_bit(5)) {
+ if (extendee_ != &_default_extendee_) {
+ extendee_->clear();
+ }
+ }
+ if (_has_bit(6)) {
+ if (default_value_ != &_default_default_value_) {
+ default_value_->clear();
+ }
+ }
+ if (_has_bit(7)) {
+ if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool FieldDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_extendee;
+ break;
+ }
+
+ // optional string extendee = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_extendee:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_extendee()));
+ if (input->ExpectTag(24)) goto parse_number;
+ break;
+ }
+
+ // optional int32 number = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_number:
+ DO_(::google::protobuf::internal::WireFormat::ReadInt32(
+ input, &number_));
+ _set_bit(1);
+ if (input->ExpectTag(32)) goto parse_label;
+ break;
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_label:
+ int value;
+ DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));
+ if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) {
+ set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value));
+ } else {
+ mutable_unknown_fields()->AddField(4)->add_varint(value);
+ }
+ if (input->ExpectTag(40)) goto parse_type;
+ break;
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+ case 5: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_type:
+ int value;
+ DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));
+ if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) {
+ set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value));
+ } else {
+ mutable_unknown_fields()->AddField(5)->add_varint(value);
+ }
+ if (input->ExpectTag(50)) goto parse_type_name;
+ break;
+ }
+
+ // optional string type_name = 6;
+ case 6: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_type_name:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_type_name()));
+ if (input->ExpectTag(58)) goto parse_default_value;
+ break;
+ }
+
+ // optional string default_value = 7;
+ case 7: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_default_value:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_default_value()));
+ if (input->ExpectTag(66)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.FieldOptions options = 8;
+ case 8: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool FieldDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // optional string extendee = 2;
+ if (_has_bit(5)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->extendee(), output));
+ }
+
+ // optional int32 number = 3;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteInt32(3, this->number(), output));
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteEnum(4, this->label(), output));
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+ if (_has_bit(3)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteEnum(5, this->type(), output));
+ }
+
+ // optional string type_name = 6;
+ if (_has_bit(4)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(6, this->type_name(), output));
+ }
+
+ // optional string default_value = 7;
+ if (_has_bit(6)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(7, this->default_value(), output));
+ }
+
+ // optional .google.protobuf.FieldOptions options = 8;
+ if (_has_bit(7)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int FieldDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional int32 number = 3;
+ if (has_number()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::Int32Size(
+ this->number());
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+ if (has_label()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::EnumSize(this->label());
+ }
+
+ // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::EnumSize(this->type());
+ }
+
+ // optional string type_name = 6;
+ if (has_type_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->type_name());
+ }
+
+ // optional string extendee = 2;
+ if (has_extendee()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->extendee());
+ }
+
+ // optional string default_value = 7;
+ if (has_default_value()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->default_value());
+ }
+
+ // optional .google.protobuf.FieldOptions options = 8;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const FieldDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const FieldDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(1)) {
+ set_number(from.number());
+ }
+ if (from._has_bit(2)) {
+ set_label(from.label());
+ }
+ if (from._has_bit(3)) {
+ set_type(from.type());
+ }
+ if (from._has_bit(4)) {
+ set_type_name(from.type_name());
+ }
+ if (from._has_bit(5)) {
+ set_extendee(from.extendee());
+ }
+ if (from._has_bit(6)) {
+ set_default_value(from.default_value());
+ }
+ if (from._has_bit(7)) {
+ mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool FieldDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* FieldDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+FieldDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* FieldDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const EnumDescriptorProto EnumDescriptorProto::default_instance_;
+
+const ::std::string EnumDescriptorProto::_default_name_;
+
+
+const int EnumDescriptorProto::_offsets_[3] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, value_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, options_),
+};
+
+EnumDescriptorProto::EnumDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::EnumOptions*>(&::google::protobuf::EnumOptions::default_instance());
+ }
+}
+
+EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+EnumDescriptorProto::~EnumDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() {
+ if (EnumDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return EnumDescriptorProto_descriptor_;
+}
+
+EnumDescriptorProto* EnumDescriptorProto::New() const {
+ return new EnumDescriptorProto;
+}
+
+void EnumDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ if (_has_bit(2)) {
+ if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
+ }
+ }
+ value_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool EnumDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_value;
+ break;
+ }
+
+ // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_value:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_value()));
+ if (input->ExpectTag(18)) goto parse_value;
+ if (input->ExpectTag(26)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.EnumOptions options = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool EnumDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+ for (int i = 0; i < value_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->value(i), output));
+ }
+
+ // optional .google.protobuf.EnumOptions options = 3;
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int EnumDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional .google.protobuf.EnumOptions options = 3;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+ total_size += 1 * value_size();
+ for (int i = 0; i < value_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->value(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const EnumDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const EnumDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ value_.MergeFrom(from.value_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(2)) {
+ mutable_options()->::google::protobuf::EnumOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool EnumDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* EnumDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+EnumDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* EnumDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const EnumValueDescriptorProto EnumValueDescriptorProto::default_instance_;
+
+const ::std::string EnumValueDescriptorProto::_default_name_;
+
+
+const int EnumValueDescriptorProto::_offsets_[3] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, number_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, options_),
+};
+
+EnumValueDescriptorProto::EnumValueDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ number_(0),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::EnumValueOptions*>(&::google::protobuf::EnumValueOptions::default_instance());
+ }
+}
+
+EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ number_(0),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+EnumValueDescriptorProto::~EnumValueDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() {
+ if (EnumValueDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return EnumValueDescriptorProto_descriptor_;
+}
+
+EnumValueDescriptorProto* EnumValueDescriptorProto::New() const {
+ return new EnumValueDescriptorProto;
+}
+
+void EnumValueDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ number_ = 0;
+ if (_has_bit(2)) {
+ if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool EnumValueDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(16)) goto parse_number;
+ break;
+ }
+
+ // optional int32 number = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_number:
+ DO_(::google::protobuf::internal::WireFormat::ReadInt32(
+ input, &number_));
+ _set_bit(1);
+ if (input->ExpectTag(26)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.EnumValueOptions options = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool EnumValueDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // optional int32 number = 2;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteInt32(2, this->number(), output));
+ }
+
+ // optional .google.protobuf.EnumValueOptions options = 3;
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int EnumValueDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional int32 number = 2;
+ if (has_number()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::Int32Size(
+ this->number());
+ }
+
+ // optional .google.protobuf.EnumValueOptions options = 3;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const EnumValueDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(1)) {
+ set_number(from.number());
+ }
+ if (from._has_bit(2)) {
+ mutable_options()->::google::protobuf::EnumValueOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool EnumValueDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* EnumValueDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+EnumValueDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* EnumValueDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const ServiceDescriptorProto ServiceDescriptorProto::default_instance_;
+
+const ::std::string ServiceDescriptorProto::_default_name_;
+
+
+const int ServiceDescriptorProto::_offsets_[3] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, method_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, options_),
+};
+
+ServiceDescriptorProto::ServiceDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::ServiceOptions*>(&::google::protobuf::ServiceOptions::default_instance());
+ }
+}
+
+ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+ServiceDescriptorProto::~ServiceDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() {
+ if (ServiceDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return ServiceDescriptorProto_descriptor_;
+}
+
+ServiceDescriptorProto* ServiceDescriptorProto::New() const {
+ return new ServiceDescriptorProto;
+}
+
+void ServiceDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ if (_has_bit(2)) {
+ if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
+ }
+ }
+ method_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool ServiceDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_method;
+ break;
+ }
+
+ // repeated .google.protobuf.MethodDescriptorProto method = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_method:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, add_method()));
+ if (input->ExpectTag(18)) goto parse_method;
+ if (input->ExpectTag(26)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.ServiceOptions options = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool ServiceDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // repeated .google.protobuf.MethodDescriptorProto method = 2;
+ for (int i = 0; i < method_.size(); i++) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->method(i), output));
+ }
+
+ // optional .google.protobuf.ServiceOptions options = 3;
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int ServiceDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional .google.protobuf.ServiceOptions options = 3;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ // repeated .google.protobuf.MethodDescriptorProto method = 2;
+ total_size += 1 * method_size();
+ for (int i = 0; i < method_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->method(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const ServiceDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const ServiceDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ method_.MergeFrom(from.method_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(2)) {
+ mutable_options()->::google::protobuf::ServiceOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ServiceDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* ServiceDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+ServiceDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* ServiceDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const MethodDescriptorProto MethodDescriptorProto::default_instance_;
+
+const ::std::string MethodDescriptorProto::_default_name_;
+const ::std::string MethodDescriptorProto::_default_input_type_;
+const ::std::string MethodDescriptorProto::_default_output_type_;
+
+const int MethodDescriptorProto::_offsets_[4] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, output_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, options_),
+};
+
+MethodDescriptorProto::MethodDescriptorProto()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ input_type_(const_cast< ::std::string*>(&_default_input_type_)),
+ output_type_(const_cast< ::std::string*>(&_default_output_type_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ options_ = const_cast< ::google::protobuf::MethodOptions*>(&::google::protobuf::MethodOptions::default_instance());
+ }
+}
+
+MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ name_(const_cast< ::std::string*>(&_default_name_)),
+ input_type_(const_cast< ::std::string*>(&_default_input_type_)),
+ output_type_(const_cast< ::std::string*>(&_default_output_type_)),
+ options_(NULL) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+MethodDescriptorProto::~MethodDescriptorProto() {
+ if (name_ != &_default_name_) {
+ delete name_;
+ }
+ if (input_type_ != &_default_input_type_) {
+ delete input_type_;
+ }
+ if (output_type_ != &_default_output_type_) {
+ delete output_type_;
+ }
+ if (this != &default_instance_) {
+ delete options_;
+ }
+}
+
+const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() {
+ if (MethodDescriptorProto_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return MethodDescriptorProto_descriptor_;
+}
+
+MethodDescriptorProto* MethodDescriptorProto::New() const {
+ return new MethodDescriptorProto;
+}
+
+void MethodDescriptorProto::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ }
+ if (_has_bit(1)) {
+ if (input_type_ != &_default_input_type_) {
+ input_type_->clear();
+ }
+ }
+ if (_has_bit(2)) {
+ if (output_type_ != &_default_output_type_) {
+ output_type_->clear();
+ }
+ }
+ if (_has_bit(3)) {
+ if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool MethodDescriptorProto::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_name()));
+ if (input->ExpectTag(18)) goto parse_input_type;
+ break;
+ }
+
+ // optional string input_type = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_input_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_input_type()));
+ if (input->ExpectTag(26)) goto parse_output_type;
+ break;
+ }
+
+ // optional string output_type = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_output_type:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_output_type()));
+ if (input->ExpectTag(34)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.MethodOptions options = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(
+ input, mutable_options()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool MethodDescriptorProto::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string name = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output));
+ }
+
+ // optional string input_type = 2;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->input_type(), output));
+ }
+
+ // optional string output_type = 3;
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->output_type(), output));
+ }
+
+ // optional .google.protobuf.MethodOptions options = 4;
+ if (_has_bit(3)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->options(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int MethodDescriptorProto::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->name());
+ }
+
+ // optional string input_type = 2;
+ if (has_input_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->input_type());
+ }
+
+ // optional string output_type = 3;
+ if (has_output_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->output_type());
+ }
+
+ // optional .google.protobuf.MethodOptions options = 4;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
+ this->options());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const MethodDescriptorProto* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const MethodDescriptorProto*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_name(from.name());
+ }
+ if (from._has_bit(1)) {
+ set_input_type(from.input_type());
+ }
+ if (from._has_bit(2)) {
+ set_output_type(from.output_type());
+ }
+ if (from._has_bit(3)) {
+ mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool MethodDescriptorProto::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* MethodDescriptorProto::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+MethodDescriptorProto::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* MethodDescriptorProto::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
+ if (FileOptions_OptimizeMode_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FileOptions_OptimizeMode_descriptor_;
+}
+bool FileOptions_OptimizeMode_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const FileOptions_OptimizeMode FileOptions::SPEED;
+const FileOptions_OptimizeMode FileOptions::CODE_SIZE;
+const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
+const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
+#endif // _MSC_VER
+const FileOptions FileOptions::default_instance_;
+
+const ::std::string FileOptions::_default_java_package_;
+const ::std::string FileOptions::_default_java_outer_classname_;
+
+
+const int FileOptions::_offsets_[4] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_),
+};
+
+FileOptions::FileOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ java_package_(const_cast< ::std::string*>(&_default_java_package_)),
+ java_outer_classname_(const_cast< ::std::string*>(&_default_java_outer_classname_)),
+ java_multiple_files_(false),
+ optimize_for_(2) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+FileOptions::FileOptions(const FileOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ java_package_(const_cast< ::std::string*>(&_default_java_package_)),
+ java_outer_classname_(const_cast< ::std::string*>(&_default_java_outer_classname_)),
+ java_multiple_files_(false),
+ optimize_for_(2) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+FileOptions::~FileOptions() {
+ if (java_package_ != &_default_java_package_) {
+ delete java_package_;
+ }
+ if (java_outer_classname_ != &_default_java_outer_classname_) {
+ delete java_outer_classname_;
+ }
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* FileOptions::descriptor() {
+ if (FileOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FileOptions_descriptor_;
+}
+
+FileOptions* FileOptions::New() const {
+ return new FileOptions;
+}
+
+void FileOptions::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (_has_bit(0)) {
+ if (java_package_ != &_default_java_package_) {
+ java_package_->clear();
+ }
+ }
+ if (_has_bit(1)) {
+ if (java_outer_classname_ != &_default_java_outer_classname_) {
+ java_outer_classname_->clear();
+ }
+ }
+ java_multiple_files_ = false;
+ optimize_for_ = 2;
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool FileOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional string java_package = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_java_package()));
+ if (input->ExpectTag(66)) goto parse_java_outer_classname;
+ break;
+ }
+
+ // optional string java_outer_classname = 8;
+ case 8: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_java_outer_classname:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_java_outer_classname()));
+ if (input->ExpectTag(72)) goto parse_optimize_for;
+ break;
+ }
+
+ // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE];
+ case 9: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_optimize_for:
+ int value;
+ DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));
+ if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) {
+ set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value));
+ } else {
+ mutable_unknown_fields()->AddField(9)->add_varint(value);
+ }
+ if (input->ExpectTag(80)) goto parse_java_multiple_files;
+ break;
+ }
+
+ // optional bool java_multiple_files = 10 [default = false];
+ case 10: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_java_multiple_files:
+ DO_(::google::protobuf::internal::WireFormat::ReadBool(
+ input, &java_multiple_files_));
+ _set_bit(2);
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool FileOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional string java_package = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->java_package(), output));
+ }
+
+ // optional string java_outer_classname = 8;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(8, this->java_outer_classname(), output));
+ }
+
+ // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE];
+ if (_has_bit(3)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteEnum(9, this->optimize_for(), output));
+ }
+
+ // optional bool java_multiple_files = 10 [default = false];
+ if (_has_bit(2)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteBool(10, this->java_multiple_files(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int FileOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string java_package = 1;
+ if (has_java_package()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->java_package());
+ }
+
+ // optional string java_outer_classname = 8;
+ if (has_java_outer_classname()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->java_outer_classname());
+ }
+
+ // optional bool java_multiple_files = 10 [default = false];
+ if (has_java_multiple_files()) {
+ total_size += 1 + 1;
+ }
+
+ // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE];
+ if (has_optimize_for()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::EnumSize(this->optimize_for());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const FileOptions* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const FileOptions*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void FileOptions::MergeFrom(const FileOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_java_package(from.java_package());
+ }
+ if (from._has_bit(1)) {
+ set_java_outer_classname(from.java_outer_classname());
+ }
+ if (from._has_bit(2)) {
+ set_java_multiple_files(from.java_multiple_files());
+ }
+ if (from._has_bit(3)) {
+ set_optimize_for(from.optimize_for());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void FileOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void FileOptions::CopyFrom(const FileOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool FileOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* FileOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+FileOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* FileOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const MessageOptions MessageOptions::default_instance_;
+
+
+const int MessageOptions::_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, message_set_wire_format_),
+};
+
+MessageOptions::MessageOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ message_set_wire_format_(false) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+MessageOptions::MessageOptions(const MessageOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ message_set_wire_format_(false) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+MessageOptions::~MessageOptions() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* MessageOptions::descriptor() {
+ if (MessageOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return MessageOptions_descriptor_;
+}
+
+MessageOptions* MessageOptions::New() const {
+ return new MessageOptions;
+}
+
+void MessageOptions::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ message_set_wire_format_ = false;
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool MessageOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional bool message_set_wire_format = 1 [default = false];
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ DO_(::google::protobuf::internal::WireFormat::ReadBool(
+ input, &message_set_wire_format_));
+ _set_bit(0);
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool MessageOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional bool message_set_wire_format = 1 [default = false];
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteBool(1, this->message_set_wire_format(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int MessageOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional bool message_set_wire_format = 1 [default = false];
+ if (has_message_set_wire_format()) {
+ total_size += 1 + 1;
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const MessageOptions* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void MessageOptions::MergeFrom(const MessageOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_message_set_wire_format(from.message_set_wire_format());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void MessageOptions::CopyFrom(const MessageOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool MessageOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* MessageOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+MessageOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* MessageOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() {
+ if (FieldOptions_CType_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FieldOptions_CType_descriptor_;
+}
+bool FieldOptions_CType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const FieldOptions_CType FieldOptions::CORD;
+const FieldOptions_CType FieldOptions::STRING_PIECE;
+const FieldOptions_CType FieldOptions::CType_MIN;
+const FieldOptions_CType FieldOptions::CType_MAX;
+#endif // _MSC_VER
+const FieldOptions FieldOptions::default_instance_;
+
+
+const ::std::string FieldOptions::_default_experimental_map_key_;
+const int FieldOptions::_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_),
+};
+
+FieldOptions::FieldOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ ctype_(1),
+ experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+FieldOptions::FieldOptions(const FieldOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0),
+ ctype_(1),
+ experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+FieldOptions::~FieldOptions() {
+ if (experimental_map_key_ != &_default_experimental_map_key_) {
+ delete experimental_map_key_;
+ }
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* FieldOptions::descriptor() {
+ if (FieldOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return FieldOptions_descriptor_;
+}
+
+FieldOptions* FieldOptions::New() const {
+ return new FieldOptions;
+}
+
+void FieldOptions::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ ctype_ = 1;
+ if (_has_bit(1)) {
+ if (experimental_map_key_ != &_default_experimental_map_key_) {
+ experimental_map_key_->clear();
+ }
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool FieldOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {
+ // optional .google.protobuf.FieldOptions.CType ctype = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ int value;
+ DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));
+ if (::google::protobuf::FieldOptions_CType_IsValid(value)) {
+ set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value));
+ } else {
+ mutable_unknown_fields()->AddField(1)->add_varint(value);
+ }
+ if (input->ExpectTag(74)) goto parse_experimental_map_key;
+ break;
+ }
+
+ // optional string experimental_map_key = 9;
+ case 9: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED) {
+ goto handle_uninterpreted;
+ }
+ parse_experimental_map_key:
+ DO_(::google::protobuf::internal::WireFormat::ReadString(input, mutable_experimental_map_key()));
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+bool FieldOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ // optional .google.protobuf.FieldOptions.CType ctype = 1;
+ if (_has_bit(0)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteEnum(1, this->ctype(), output));
+ }
+
+ // optional string experimental_map_key = 9;
+ if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteString(9, this->experimental_map_key(), output));
+ }
+
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int FieldOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .google.protobuf.FieldOptions.CType ctype = 1;
+ if (has_ctype()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::EnumSize(this->ctype());
+ }
+
+ // optional string experimental_map_key = 9;
+ if (has_experimental_map_key()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormat::StringSize(this->experimental_map_key());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const FieldOptions* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const FieldOptions*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(
+ descriptor(), *from.GetReflection(), &_reflection_);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void FieldOptions::MergeFrom(const FieldOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from._has_bit(0)) {
+ set_ctype(from.ctype());
+ }
+ if (from._has_bit(1)) {
+ set_experimental_map_key(from.experimental_map_key());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void FieldOptions::CopyFrom(const FieldOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool FieldOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* FieldOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+FieldOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* FieldOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const EnumOptions EnumOptions::default_instance_;
+
+const int EnumOptions::_offsets_[1] = {
+};
+
+EnumOptions::EnumOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+EnumOptions::EnumOptions(const EnumOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+EnumOptions::~EnumOptions() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* EnumOptions::descriptor() {
+ if (EnumOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return EnumOptions_descriptor_;
+}
+
+EnumOptions* EnumOptions::New() const {
+ return new EnumOptions;
+}
+
+void EnumOptions::Clear() {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool EnumOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ }
+ return true;
+#undef DO_
+}
+
+bool EnumOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int EnumOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+}
+
+void EnumOptions::MergeFrom(const EnumOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void EnumOptions::CopyFrom(const EnumOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool EnumOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* EnumOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+EnumOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* EnumOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const EnumValueOptions EnumValueOptions::default_instance_;
+
+const int EnumValueOptions::_offsets_[1] = {
+};
+
+EnumValueOptions::EnumValueOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+EnumValueOptions::EnumValueOptions(const EnumValueOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+EnumValueOptions::~EnumValueOptions() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() {
+ if (EnumValueOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return EnumValueOptions_descriptor_;
+}
+
+EnumValueOptions* EnumValueOptions::New() const {
+ return new EnumValueOptions;
+}
+
+void EnumValueOptions::Clear() {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool EnumValueOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ }
+ return true;
+#undef DO_
+}
+
+bool EnumValueOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int EnumValueOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+}
+
+void EnumValueOptions::MergeFrom(const EnumValueOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool EnumValueOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* EnumValueOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+EnumValueOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* EnumValueOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const ServiceOptions ServiceOptions::default_instance_;
+
+const int ServiceOptions::_offsets_[1] = {
+};
+
+ServiceOptions::ServiceOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+ServiceOptions::ServiceOptions(const ServiceOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+ServiceOptions::~ServiceOptions() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* ServiceOptions::descriptor() {
+ if (ServiceOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return ServiceOptions_descriptor_;
+}
+
+ServiceOptions* ServiceOptions::New() const {
+ return new ServiceOptions;
+}
+
+void ServiceOptions::Clear() {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool ServiceOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ }
+ return true;
+#undef DO_
+}
+
+bool ServiceOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int ServiceOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+}
+
+void ServiceOptions::MergeFrom(const ServiceOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ServiceOptions::CopyFrom(const ServiceOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ServiceOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* ServiceOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+ServiceOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* ServiceOptions::GetReflection() {
+ return &_reflection_;
+}
+
+// ===================================================================
+
+const MethodOptions MethodOptions::default_instance_;
+
+const int MethodOptions::_offsets_[1] = {
+};
+
+MethodOptions::MethodOptions()
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (this == &default_instance_) {
+ }
+}
+
+MethodOptions::MethodOptions(const MethodOptions& from)
+ : _reflection_(descriptor(),
+ this, &default_instance_,
+ _offsets_, _has_bits_, NULL),
+ _cached_size_(0) {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ MergeFrom(from);
+}
+
+MethodOptions::~MethodOptions() {
+ if (this != &default_instance_) {
+ }
+}
+
+const ::google::protobuf::Descriptor* MethodOptions::descriptor() {
+ if (MethodOptions_descriptor_ == NULL) proto_BuildDescriptors_google_2fprotobuf_2fdescriptor_2eproto();
+ return MethodOptions_descriptor_;
+}
+
+MethodOptions* MethodOptions::New() const {
+ return new MethodOptions;
+}
+
+void MethodOptions::Clear() {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool MethodOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ }
+ return true;
+#undef DO_
+}
+
+bool MethodOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ if (!unknown_fields().empty()) {
+ DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output));
+ }
+ return true;
+#undef DO_
+}
+
+int MethodOptions::ByteSize() const {
+ int total_size = 0;
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ _cached_size_ = total_size;
+ return total_size;
+}
+
+void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+}
+
+void MethodOptions::MergeFrom(const MethodOptions& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void MethodOptions::CopyFrom(const MethodOptions& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool MethodOptions::IsInitialized() const {
+
+ return true;
+}
+
+const ::google::protobuf::Descriptor* MethodOptions::GetDescriptor() const {
+ return descriptor();
+}
+
+const ::google::protobuf::Message::Reflection*
+MethodOptions::GetReflection() const {
+ return &_reflection_;
+}
+
+::google::protobuf::Message::Reflection* MethodOptions::GetReflection() {
+ return &_reflection_;
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
new file mode 100644
index 00000000..892f92d0
--- /dev/null
+++ b/src/google/protobuf/descriptor.pb.h
@@ -0,0 +1,2958 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 2000000
+#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 2000001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+
+namespace google {
+namespace protobuf {
+
+class FileDescriptorProto;
+class DescriptorProto;
+class DescriptorProto_ExtensionRange;
+class FieldDescriptorProto;
+class EnumDescriptorProto;
+class EnumValueDescriptorProto;
+class ServiceDescriptorProto;
+class MethodDescriptorProto;
+class FileOptions;
+class MessageOptions;
+class FieldOptions;
+class EnumOptions;
+class EnumValueOptions;
+class ServiceOptions;
+class MethodOptions;
+
+enum FieldDescriptorProto_Type {
+ 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,
+};
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
+LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
+const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
+const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
+
+enum FieldDescriptorProto_Label {
+ FieldDescriptorProto_Label_LABEL_OPTIONAL = 1,
+ FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
+ FieldDescriptorProto_Label_LABEL_REPEATED = 3,
+};
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
+LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
+const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
+const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
+
+enum FileOptions_OptimizeMode {
+ FileOptions_OptimizeMode_SPEED = 1,
+ FileOptions_OptimizeMode_CODE_SIZE = 2,
+};
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
+LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
+const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
+const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_CODE_SIZE;
+
+enum FieldOptions_CType {
+ FieldOptions_CType_CORD = 1,
+ FieldOptions_CType_STRING_PIECE = 2,
+};
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
+LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
+const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD;
+const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message {
+ public:
+ FileDescriptorProto();
+ virtual ~FileDescriptorProto();
+
+ FileDescriptorProto(const FileDescriptorProto& from);
+
+ inline FileDescriptorProto& operator=(const FileDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const FileDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ FileDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const FileDescriptorProto& from);
+ void MergeFrom(const FileDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // optional string package = 2;
+ inline bool has_package() const;
+ inline void clear_package();
+ inline const ::std::string& package() const;
+ inline void set_package(const ::std::string& value);
+ inline void set_package(const char* value);
+ inline ::std::string* mutable_package();
+
+ // repeated string dependency = 3;
+ inline int dependency_size() const;
+ inline void clear_dependency();
+ inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
+ inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
+ inline const ::std::string& dependency(int index) const;
+ inline ::std::string* mutable_dependency(int index);
+ inline void set_dependency(int index, const ::std::string& value);
+ inline void set_dependency(int index, const char* value);
+ inline ::std::string* add_dependency();
+ inline void add_dependency(const ::std::string& value);
+ inline void add_dependency(const char* value);
+
+ // repeated .google.protobuf.DescriptorProto message_type = 4;
+ inline int message_type_size() const;
+ inline void clear_message_type();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& message_type() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type();
+ inline const ::google::protobuf::DescriptorProto& message_type(int index) const;
+ inline ::google::protobuf::DescriptorProto* mutable_message_type(int index);
+ inline ::google::protobuf::DescriptorProto* add_message_type();
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+ inline int enum_type_size() const;
+ inline void clear_enum_type();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type();
+ inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+ inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+ inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
+
+ // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+ inline int service_size() const;
+ inline void clear_service();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& service() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service();
+ inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
+ inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
+ inline ::google::protobuf::ServiceDescriptorProto* add_service();
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+ inline int extension_size() const;
+ inline void clear_extension();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension();
+ inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+ inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+ inline ::google::protobuf::FieldDescriptorProto* add_extension();
+
+ // optional .google.protobuf.FileOptions options = 8;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::FileOptions& options() const;
+ inline ::google::protobuf::FileOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::std::string* package_;
+ static const ::std::string _default_package_;
+ ::google::protobuf::RepeatedPtrField< ::std::string> dependency_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > message_type_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
+ ::google::protobuf::FileOptions* options_;
+
+ static const FileDescriptorProto default_instance_;
+ static const int _offsets_[8];
+
+ ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message {
+ public:
+ DescriptorProto_ExtensionRange();
+ virtual ~DescriptorProto_ExtensionRange();
+
+ DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from);
+
+ inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const DescriptorProto_ExtensionRange& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ DescriptorProto_ExtensionRange* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const DescriptorProto_ExtensionRange& from);
+ void MergeFrom(const DescriptorProto_ExtensionRange& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional int32 start = 1;
+ inline bool has_start() const;
+ inline void clear_start();
+ inline ::google::protobuf::int32 start() const;
+ inline void set_start(::google::protobuf::int32 value);
+
+ // optional int32 end = 2;
+ inline bool has_end() const;
+ inline void clear_end();
+ inline ::google::protobuf::int32 end() const;
+ inline void set_end(::google::protobuf::int32 value);
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::google::protobuf::int32 start_;
+ ::google::protobuf::int32 end_;
+
+ static const DescriptorProto_ExtensionRange default_instance_;
+ static const int _offsets_[2];
+
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
+ public:
+ DescriptorProto();
+ virtual ~DescriptorProto();
+
+ DescriptorProto(const DescriptorProto& from);
+
+ inline DescriptorProto& operator=(const DescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const DescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ DescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const DescriptorProto& from);
+ void MergeFrom(const DescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ typedef DescriptorProto_ExtensionRange ExtensionRange;
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // repeated .google.protobuf.FieldDescriptorProto field = 2;
+ inline int field_size() const;
+ inline void clear_field();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& field() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field();
+ inline const ::google::protobuf::FieldDescriptorProto& field(int index) const;
+ inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
+ inline ::google::protobuf::FieldDescriptorProto* add_field();
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+ inline int extension_size() const;
+ inline void clear_extension();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension();
+ inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+ inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+ inline ::google::protobuf::FieldDescriptorProto* add_extension();
+
+ // repeated .google.protobuf.DescriptorProto nested_type = 3;
+ inline int nested_type_size() const;
+ inline void clear_nested_type();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& nested_type() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type();
+ inline const ::google::protobuf::DescriptorProto& nested_type(int index) const;
+ inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
+ inline ::google::protobuf::DescriptorProto* add_nested_type();
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+ inline int enum_type_size() const;
+ inline void clear_enum_type();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type();
+ inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+ inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+ inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
+
+ // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+ inline int extension_range_size() const;
+ inline void clear_extension_range();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& extension_range() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range();
+ inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const;
+ inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
+ inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range();
+
+ // optional .google.protobuf.MessageOptions options = 7;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::MessageOptions& options() const;
+ inline ::google::protobuf::MessageOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > nested_type_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_;
+ ::google::protobuf::MessageOptions* options_;
+
+ static const DescriptorProto default_instance_;
+ static const int _offsets_[7];
+
+ ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message {
+ public:
+ FieldDescriptorProto();
+ virtual ~FieldDescriptorProto();
+
+ FieldDescriptorProto(const FieldDescriptorProto& from);
+
+ inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const FieldDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ FieldDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const FieldDescriptorProto& from);
+ void MergeFrom(const FieldDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ typedef FieldDescriptorProto_Type Type;
+ static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE;
+ static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT;
+ static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64;
+ static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64;
+ static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32;
+ static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64;
+ static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32;
+ static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL;
+ static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING;
+ static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP;
+ static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE;
+ static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES;
+ static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32;
+ static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM;
+ static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32;
+ static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64;
+ static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32;
+ static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64;
+ static inline const ::google::protobuf::EnumDescriptor*
+ Type_descriptor() {
+ return FieldDescriptorProto_Type_descriptor();
+ }
+ static inline bool Type_IsValid(int value) {
+ return FieldDescriptorProto_Type_IsValid(value);
+ }
+ static const Type Type_MIN =
+ FieldDescriptorProto_Type_Type_MIN;
+ static const Type Type_MAX =
+ FieldDescriptorProto_Type_Type_MAX;
+
+ typedef FieldDescriptorProto_Label Label;
+ static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
+ static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
+ static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED;
+ static inline const ::google::protobuf::EnumDescriptor*
+ Label_descriptor() {
+ return FieldDescriptorProto_Label_descriptor();
+ }
+ static inline bool Label_IsValid(int value) {
+ return FieldDescriptorProto_Label_IsValid(value);
+ }
+ static const Label Label_MIN =
+ FieldDescriptorProto_Label_Label_MIN;
+ static const Label Label_MAX =
+ FieldDescriptorProto_Label_Label_MAX;
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // optional int32 number = 3;
+ inline bool has_number() const;
+ inline void clear_number();
+ inline ::google::protobuf::int32 number() const;
+ inline void set_number(::google::protobuf::int32 value);
+
+ // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+ inline bool has_label() const;
+ inline void clear_label();
+ inline ::google::protobuf::FieldDescriptorProto_Label label() const;
+ inline void set_label(::google::protobuf::FieldDescriptorProto_Label value);
+
+ // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+ inline bool has_type() const;
+ inline void clear_type();
+ inline ::google::protobuf::FieldDescriptorProto_Type type() const;
+ inline void set_type(::google::protobuf::FieldDescriptorProto_Type value);
+
+ // optional string type_name = 6;
+ inline bool has_type_name() const;
+ inline void clear_type_name();
+ inline const ::std::string& type_name() const;
+ inline void set_type_name(const ::std::string& value);
+ inline void set_type_name(const char* value);
+ inline ::std::string* mutable_type_name();
+
+ // optional string extendee = 2;
+ inline bool has_extendee() const;
+ inline void clear_extendee();
+ inline const ::std::string& extendee() const;
+ inline void set_extendee(const ::std::string& value);
+ inline void set_extendee(const char* value);
+ inline ::std::string* mutable_extendee();
+
+ // optional string default_value = 7;
+ inline bool has_default_value() const;
+ inline void clear_default_value();
+ inline const ::std::string& default_value() const;
+ inline void set_default_value(const ::std::string& value);
+ inline void set_default_value(const char* value);
+ inline ::std::string* mutable_default_value();
+
+ // optional .google.protobuf.FieldOptions options = 8;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::FieldOptions& options() const;
+ inline ::google::protobuf::FieldOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::google::protobuf::int32 number_;
+ int label_;
+ int type_;
+ ::std::string* type_name_;
+ static const ::std::string _default_type_name_;
+ ::std::string* extendee_;
+ static const ::std::string _default_extendee_;
+ ::std::string* default_value_;
+ static const ::std::string _default_default_value_;
+ ::google::protobuf::FieldOptions* options_;
+
+ static const FieldDescriptorProto default_instance_;
+ static const int _offsets_[8];
+
+ ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message {
+ public:
+ EnumDescriptorProto();
+ virtual ~EnumDescriptorProto();
+
+ EnumDescriptorProto(const EnumDescriptorProto& from);
+
+ inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const EnumDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ EnumDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const EnumDescriptorProto& from);
+ void MergeFrom(const EnumDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+ inline int value_size() const;
+ inline void clear_value();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& value() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value();
+ inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
+ inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
+ inline ::google::protobuf::EnumValueDescriptorProto* add_value();
+
+ // optional .google.protobuf.EnumOptions options = 3;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::EnumOptions& options() const;
+ inline ::google::protobuf::EnumOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_;
+ ::google::protobuf::EnumOptions* options_;
+
+ static const EnumDescriptorProto default_instance_;
+ static const int _offsets_[3];
+
+ ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message {
+ public:
+ EnumValueDescriptorProto();
+ virtual ~EnumValueDescriptorProto();
+
+ EnumValueDescriptorProto(const EnumValueDescriptorProto& from);
+
+ inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const EnumValueDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ EnumValueDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const EnumValueDescriptorProto& from);
+ void MergeFrom(const EnumValueDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // optional int32 number = 2;
+ inline bool has_number() const;
+ inline void clear_number();
+ inline ::google::protobuf::int32 number() const;
+ inline void set_number(::google::protobuf::int32 value);
+
+ // optional .google.protobuf.EnumValueOptions options = 3;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::EnumValueOptions& options() const;
+ inline ::google::protobuf::EnumValueOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::google::protobuf::int32 number_;
+ ::google::protobuf::EnumValueOptions* options_;
+
+ static const EnumValueDescriptorProto default_instance_;
+ static const int _offsets_[3];
+
+ ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message {
+ public:
+ ServiceDescriptorProto();
+ virtual ~ServiceDescriptorProto();
+
+ ServiceDescriptorProto(const ServiceDescriptorProto& from);
+
+ inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const ServiceDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ ServiceDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const ServiceDescriptorProto& from);
+ void MergeFrom(const ServiceDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // repeated .google.protobuf.MethodDescriptorProto method = 2;
+ inline int method_size() const;
+ inline void clear_method();
+ inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& method() const;
+ inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method();
+ inline const ::google::protobuf::MethodDescriptorProto& method(int index) const;
+ inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
+ inline ::google::protobuf::MethodDescriptorProto* add_method();
+
+ // optional .google.protobuf.ServiceOptions options = 3;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::ServiceOptions& options() const;
+ inline ::google::protobuf::ServiceOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_;
+ ::google::protobuf::ServiceOptions* options_;
+
+ static const ServiceDescriptorProto default_instance_;
+ static const int _offsets_[3];
+
+ ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message {
+ public:
+ MethodDescriptorProto();
+ virtual ~MethodDescriptorProto();
+
+ MethodDescriptorProto(const MethodDescriptorProto& from);
+
+ inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const MethodDescriptorProto& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ MethodDescriptorProto* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const MethodDescriptorProto& from);
+ void MergeFrom(const MethodDescriptorProto& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string name = 1;
+ inline bool has_name() const;
+ inline void clear_name();
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline ::std::string* mutable_name();
+
+ // optional string input_type = 2;
+ inline bool has_input_type() const;
+ inline void clear_input_type();
+ inline const ::std::string& input_type() const;
+ inline void set_input_type(const ::std::string& value);
+ inline void set_input_type(const char* value);
+ inline ::std::string* mutable_input_type();
+
+ // optional string output_type = 3;
+ inline bool has_output_type() const;
+ inline void clear_output_type();
+ inline const ::std::string& output_type() const;
+ inline void set_output_type(const ::std::string& value);
+ inline void set_output_type(const char* value);
+ inline ::std::string* mutable_output_type();
+
+ // optional .google.protobuf.MethodOptions options = 4;
+ inline bool has_options() const;
+ inline void clear_options();
+ inline const ::google::protobuf::MethodOptions& options() const;
+ inline ::google::protobuf::MethodOptions* mutable_options();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* name_;
+ static const ::std::string _default_name_;
+ ::std::string* input_type_;
+ static const ::std::string _default_input_type_;
+ ::std::string* output_type_;
+ static const ::std::string _default_output_type_;
+ ::google::protobuf::MethodOptions* options_;
+
+ static const MethodDescriptorProto default_instance_;
+ static const int _offsets_[4];
+
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
+ public:
+ FileOptions();
+ virtual ~FileOptions();
+
+ FileOptions(const FileOptions& from);
+
+ inline FileOptions& operator=(const FileOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const FileOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ FileOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const FileOptions& from);
+ void MergeFrom(const FileOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ typedef FileOptions_OptimizeMode OptimizeMode;
+ static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
+ static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ OptimizeMode_descriptor() {
+ return FileOptions_OptimizeMode_descriptor();
+ }
+ static inline bool OptimizeMode_IsValid(int value) {
+ return FileOptions_OptimizeMode_IsValid(value);
+ }
+ static const OptimizeMode OptimizeMode_MIN =
+ FileOptions_OptimizeMode_OptimizeMode_MIN;
+ static const OptimizeMode OptimizeMode_MAX =
+ FileOptions_OptimizeMode_OptimizeMode_MAX;
+
+ // accessors -------------------------------------------------------
+
+ // optional string java_package = 1;
+ inline bool has_java_package() const;
+ inline void clear_java_package();
+ inline const ::std::string& java_package() const;
+ inline void set_java_package(const ::std::string& value);
+ inline void set_java_package(const char* value);
+ inline ::std::string* mutable_java_package();
+
+ // optional string java_outer_classname = 8;
+ inline bool has_java_outer_classname() const;
+ inline void clear_java_outer_classname();
+ inline const ::std::string& java_outer_classname() const;
+ inline void set_java_outer_classname(const ::std::string& value);
+ inline void set_java_outer_classname(const char* value);
+ inline ::std::string* mutable_java_outer_classname();
+
+ // optional bool java_multiple_files = 10 [default = false];
+ inline bool has_java_multiple_files() const;
+ inline void clear_java_multiple_files();
+ inline bool java_multiple_files() const;
+ inline void set_java_multiple_files(bool value);
+
+ // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE];
+ inline bool has_optimize_for() const;
+ inline void clear_optimize_for();
+ inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
+ inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ ::std::string* java_package_;
+ static const ::std::string _default_java_package_;
+ ::std::string* java_outer_classname_;
+ static const ::std::string _default_java_outer_classname_;
+ bool java_multiple_files_;
+ int optimize_for_;
+
+ static const FileOptions default_instance_;
+ static const int _offsets_[4];
+
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
+ public:
+ MessageOptions();
+ virtual ~MessageOptions();
+
+ MessageOptions(const MessageOptions& from);
+
+ inline MessageOptions& operator=(const MessageOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const MessageOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ MessageOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const MessageOptions& from);
+ void MergeFrom(const MessageOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional bool message_set_wire_format = 1 [default = false];
+ inline bool has_message_set_wire_format() const;
+ inline void clear_message_set_wire_format();
+ inline bool message_set_wire_format() const;
+ inline void set_message_set_wire_format(bool value);
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ bool message_set_wire_format_;
+
+ static const MessageOptions default_instance_;
+ static const int _offsets_[1];
+
+ ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
+ public:
+ FieldOptions();
+ virtual ~FieldOptions();
+
+ FieldOptions(const FieldOptions& from);
+
+ inline FieldOptions& operator=(const FieldOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const FieldOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ FieldOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const FieldOptions& from);
+ void MergeFrom(const FieldOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ typedef FieldOptions_CType CType;
+ static const CType CORD = FieldOptions_CType_CORD;
+ static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ CType_descriptor() {
+ return FieldOptions_CType_descriptor();
+ }
+ static inline bool CType_IsValid(int value) {
+ return FieldOptions_CType_IsValid(value);
+ }
+ static const CType CType_MIN =
+ FieldOptions_CType_CType_MIN;
+ static const CType CType_MAX =
+ FieldOptions_CType_CType_MAX;
+
+ // accessors -------------------------------------------------------
+
+ // optional .google.protobuf.FieldOptions.CType ctype = 1;
+ inline bool has_ctype() const;
+ inline void clear_ctype();
+ inline ::google::protobuf::FieldOptions_CType ctype() const;
+ inline void set_ctype(::google::protobuf::FieldOptions_CType value);
+
+ // optional string experimental_map_key = 9;
+ inline bool has_experimental_map_key() const;
+ inline void clear_experimental_map_key();
+ inline const ::std::string& experimental_map_key() const;
+ inline void set_experimental_map_key(const ::std::string& value);
+ inline void set_experimental_map_key(const char* value);
+ inline ::std::string* mutable_experimental_map_key();
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+ int ctype_;
+ ::std::string* experimental_map_key_;
+ static const ::std::string _default_experimental_map_key_;
+
+ static const FieldOptions default_instance_;
+ static const int _offsets_[2];
+
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
+ public:
+ EnumOptions();
+ virtual ~EnumOptions();
+
+ EnumOptions(const EnumOptions& from);
+
+ inline EnumOptions& operator=(const EnumOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const EnumOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ EnumOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const EnumOptions& from);
+ void MergeFrom(const EnumOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+
+ static const EnumOptions default_instance_;
+ static const int _offsets_[1];
+
+ ::google::protobuf::uint32 _has_bits_[1];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
+ public:
+ EnumValueOptions();
+ virtual ~EnumValueOptions();
+
+ EnumValueOptions(const EnumValueOptions& from);
+
+ inline EnumValueOptions& operator=(const EnumValueOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const EnumValueOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ EnumValueOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const EnumValueOptions& from);
+ void MergeFrom(const EnumValueOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+
+ static const EnumValueOptions default_instance_;
+ static const int _offsets_[1];
+
+ ::google::protobuf::uint32 _has_bits_[1];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
+ public:
+ ServiceOptions();
+ virtual ~ServiceOptions();
+
+ ServiceOptions(const ServiceOptions& from);
+
+ inline ServiceOptions& operator=(const ServiceOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const ServiceOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ ServiceOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const ServiceOptions& from);
+ void MergeFrom(const ServiceOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+
+ static const ServiceOptions default_instance_;
+ static const int _offsets_[1];
+
+ ::google::protobuf::uint32 _has_bits_[1];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
+ public:
+ MethodOptions();
+ virtual ~MethodOptions();
+
+ MethodOptions(const MethodOptions& from);
+
+ inline MethodOptions& operator=(const MethodOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline static const MethodOptions& default_instance() {
+ return default_instance_;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _reflection_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _reflection_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+
+ // implements Message ----------------------------------------------
+
+ MethodOptions* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const MethodOptions& from);
+ void MergeFrom(const MethodOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+ int ByteSize() const;
+
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ bool SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SetCachedSize(int size) const { _cached_size_ = size; }
+ public:
+
+ const ::google::protobuf::Descriptor* GetDescriptor() const;
+ const ::google::protobuf::Message::Reflection* GetReflection() const;
+ ::google::protobuf::Message::Reflection* GetReflection();
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ private:
+ ::google::protobuf::internal::GeneratedMessageReflection _reflection_;
+ mutable int _cached_size_;
+
+
+ static const MethodOptions default_instance_;
+ static const int _offsets_[1];
+
+ ::google::protobuf::uint32 _has_bits_[1];
+
+ // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+ inline bool _has_bit(int index) const {
+ return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+ }
+ inline void _set_bit(int index) {
+ _has_bits_[index / 32] |= (1u << (index % 32));
+ }
+ inline void _clear_bit(int index) {
+ _has_bits_[index / 32] &= ~(1u << (index % 32));
+ }
+};
+// ===================================================================
+
+
+// ===================================================================
+
+
+// ===================================================================
+
+// FileDescriptorProto
+
+// optional string name = 1;
+inline bool FileDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void FileDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& FileDescriptorProto::name() const {
+ return *name_;
+}
+inline void FileDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void FileDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* FileDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// optional string package = 2;
+inline bool FileDescriptorProto::has_package() const {
+ return _has_bit(1);
+}
+inline void FileDescriptorProto::clear_package() {
+ if (package_ != &_default_package_) {
+ package_->clear();
+ }
+ _clear_bit(1);
+}
+inline const ::std::string& FileDescriptorProto::package() const {
+ return *package_;
+}
+inline void FileDescriptorProto::set_package(const ::std::string& value) {
+ _set_bit(1);
+ if (package_ == &_default_package_) {
+ package_ = new ::std::string;
+ }
+ package_->assign(value);
+}
+inline void FileDescriptorProto::set_package(const char* value) {
+ _set_bit(1);
+ if (package_ == &_default_package_) {
+ package_ = new ::std::string;
+ }
+ package_->assign(value);
+}
+inline ::std::string* FileDescriptorProto::mutable_package() {
+ _set_bit(1);
+ if (package_ == &_default_package_) {
+ package_ = new ::std::string;
+ }
+ return package_;
+}
+
+// repeated string dependency = 3;
+inline int FileDescriptorProto::dependency_size() const {
+ return dependency_.size();
+}
+inline void FileDescriptorProto::clear_dependency() {
+ dependency_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FileDescriptorProto::dependency() const {
+ return dependency_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+FileDescriptorProto::mutable_dependency() {
+ return &dependency_;
+}
+inline const ::std::string& FileDescriptorProto::dependency(int index) const {
+ return dependency_.Get(index);
+}
+inline ::std::string* FileDescriptorProto::mutable_dependency(int index) {
+ return dependency_.Mutable(index);
+}
+inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
+ dependency_.Mutable(index)->assign(value);
+}
+inline void FileDescriptorProto::set_dependency(int index, const char* value) {
+ dependency_.Mutable(index)->assign(value);
+}
+inline ::std::string* FileDescriptorProto::add_dependency() {
+ return dependency_.Add();
+}
+inline void FileDescriptorProto::add_dependency(const ::std::string& value) {
+ dependency_.Add()->assign(value);
+}
+inline void FileDescriptorProto::add_dependency(const char* value) {
+ dependency_.Add()->assign(value);
+}
+
+// repeated .google.protobuf.DescriptorProto message_type = 4;
+inline int FileDescriptorProto::message_type_size() const {
+ return message_type_.size();
+}
+inline void FileDescriptorProto::clear_message_type() {
+ message_type_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+ return message_type_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+FileDescriptorProto::mutable_message_type() {
+ return &message_type_;
+}
+inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+ return message_type_.Get(index);
+}
+inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+ return message_type_.Mutable(index);
+}
+inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() {
+ return message_type_.Add();
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+inline int FileDescriptorProto::enum_type_size() const {
+ return enum_type_.size();
+}
+inline void FileDescriptorProto::clear_enum_type() {
+ enum_type_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+ return enum_type_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+FileDescriptorProto::mutable_enum_type() {
+ return &enum_type_;
+}
+inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+ return enum_type_.Get(index);
+}
+inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+ return enum_type_.Mutable(index);
+}
+inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+ return enum_type_.Add();
+}
+
+// repeated .google.protobuf.ServiceDescriptorProto service = 6;
+inline int FileDescriptorProto::service_size() const {
+ return service_.size();
+}
+inline void FileDescriptorProto::clear_service() {
+ service_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+ return service_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+FileDescriptorProto::mutable_service() {
+ return &service_;
+}
+inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+ return service_.Get(index);
+}
+inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+ return service_.Mutable(index);
+}
+inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+ return service_.Add();
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 7;
+inline int FileDescriptorProto::extension_size() const {
+ return extension_.size();
+}
+inline void FileDescriptorProto::clear_extension() {
+ extension_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+ return extension_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+FileDescriptorProto::mutable_extension() {
+ return &extension_;
+}
+inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+ return extension_.Get(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+ return extension_.Mutable(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+ return extension_.Add();
+}
+
+// optional .google.protobuf.FileOptions options = 8;
+inline bool FileDescriptorProto::has_options() const {
+ return _has_bit(7);
+}
+inline void FileDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
+ _clear_bit(7);
+}
+inline const ::google::protobuf::FileOptions& FileDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
+ _set_bit(7);
+ if (options_ == NULL) options_ = new ::google::protobuf::FileOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ExtensionRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ExtensionRange::has_start() const {
+ return _has_bit(0);
+}
+inline void DescriptorProto_ExtensionRange::clear_start() {
+ start_ = 0;
+ _clear_bit(0);
+}
+inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const {
+ return start_;
+}
+inline void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) {
+ _set_bit(0);
+ start_ = value;
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ExtensionRange::has_end() const {
+ return _has_bit(1);
+}
+inline void DescriptorProto_ExtensionRange::clear_end() {
+ end_ = 0;
+ _clear_bit(1);
+}
+inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const {
+ return end_;
+}
+inline void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) {
+ _set_bit(1);
+ end_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto
+
+// optional string name = 1;
+inline bool DescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void DescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& DescriptorProto::name() const {
+ return *name_;
+}
+inline void DescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void DescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* DescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto field = 2;
+inline int DescriptorProto::field_size() const {
+ return field_.size();
+}
+inline void DescriptorProto::clear_field() {
+ field_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::field() const {
+ return field_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_field() {
+ return &field_;
+}
+inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
+ return field_.Get(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+ return field_.Mutable(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() {
+ return field_.Add();
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 6;
+inline int DescriptorProto::extension_size() const {
+ return extension_.size();
+}
+inline void DescriptorProto::clear_extension() {
+ extension_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+ return extension_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_extension() {
+ return &extension_;
+}
+inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+ return extension_.Get(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+ return extension_.Mutable(index);
+}
+inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() {
+ return extension_.Add();
+}
+
+// repeated .google.protobuf.DescriptorProto nested_type = 3;
+inline int DescriptorProto::nested_type_size() const {
+ return nested_type_.size();
+}
+inline void DescriptorProto::clear_nested_type() {
+ nested_type_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+DescriptorProto::nested_type() const {
+ return nested_type_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+DescriptorProto::mutable_nested_type() {
+ return &nested_type_;
+}
+inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
+ return nested_type_.Get(index);
+}
+inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+ return nested_type_.Mutable(index);
+}
+inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() {
+ return nested_type_.Add();
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+inline int DescriptorProto::enum_type_size() const {
+ return enum_type_.size();
+}
+inline void DescriptorProto::clear_enum_type() {
+ enum_type_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+ return enum_type_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+DescriptorProto::mutable_enum_type() {
+ return &enum_type_;
+}
+inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+ return enum_type_.Get(index);
+}
+inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+ return enum_type_.Mutable(index);
+}
+inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+ return enum_type_.Add();
+}
+
+// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+inline int DescriptorProto::extension_range_size() const {
+ return extension_range_.size();
+}
+inline void DescriptorProto::clear_extension_range() {
+ extension_range_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+ return extension_range_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+DescriptorProto::mutable_extension_range() {
+ return &extension_range_;
+}
+inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+ return extension_range_.Get(index);
+}
+inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+ return extension_range_.Mutable(index);
+}
+inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+ return extension_range_.Add();
+}
+
+// optional .google.protobuf.MessageOptions options = 7;
+inline bool DescriptorProto::has_options() const {
+ return _has_bit(6);
+}
+inline void DescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
+ _clear_bit(6);
+}
+inline const ::google::protobuf::MessageOptions& DescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
+ _set_bit(6);
+ if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// FieldDescriptorProto
+
+// optional string name = 1;
+inline bool FieldDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void FieldDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& FieldDescriptorProto::name() const {
+ return *name_;
+}
+inline void FieldDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void FieldDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* FieldDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// optional int32 number = 3;
+inline bool FieldDescriptorProto::has_number() const {
+ return _has_bit(1);
+}
+inline void FieldDescriptorProto::clear_number() {
+ number_ = 0;
+ _clear_bit(1);
+}
+inline ::google::protobuf::int32 FieldDescriptorProto::number() const {
+ return number_;
+}
+inline void FieldDescriptorProto::set_number(::google::protobuf::int32 value) {
+ _set_bit(1);
+ number_ = value;
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+inline bool FieldDescriptorProto::has_label() const {
+ return _has_bit(2);
+}
+inline void FieldDescriptorProto::clear_label() {
+ label_ = 1;
+ _clear_bit(2);
+}
+inline ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+ return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_);
+}
+inline void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) {
+ GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
+ _set_bit(2);
+ label_ = value;
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+inline bool FieldDescriptorProto::has_type() const {
+ return _has_bit(3);
+}
+inline void FieldDescriptorProto::clear_type() {
+ type_ = 1;
+ _clear_bit(3);
+}
+inline ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+ return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_);
+}
+inline void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) {
+ GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
+ _set_bit(3);
+ type_ = value;
+}
+
+// optional string type_name = 6;
+inline bool FieldDescriptorProto::has_type_name() const {
+ return _has_bit(4);
+}
+inline void FieldDescriptorProto::clear_type_name() {
+ if (type_name_ != &_default_type_name_) {
+ type_name_->clear();
+ }
+ _clear_bit(4);
+}
+inline const ::std::string& FieldDescriptorProto::type_name() const {
+ return *type_name_;
+}
+inline void FieldDescriptorProto::set_type_name(const ::std::string& value) {
+ _set_bit(4);
+ if (type_name_ == &_default_type_name_) {
+ type_name_ = new ::std::string;
+ }
+ type_name_->assign(value);
+}
+inline void FieldDescriptorProto::set_type_name(const char* value) {
+ _set_bit(4);
+ if (type_name_ == &_default_type_name_) {
+ type_name_ = new ::std::string;
+ }
+ type_name_->assign(value);
+}
+inline ::std::string* FieldDescriptorProto::mutable_type_name() {
+ _set_bit(4);
+ if (type_name_ == &_default_type_name_) {
+ type_name_ = new ::std::string;
+ }
+ return type_name_;
+}
+
+// optional string extendee = 2;
+inline bool FieldDescriptorProto::has_extendee() const {
+ return _has_bit(5);
+}
+inline void FieldDescriptorProto::clear_extendee() {
+ if (extendee_ != &_default_extendee_) {
+ extendee_->clear();
+ }
+ _clear_bit(5);
+}
+inline const ::std::string& FieldDescriptorProto::extendee() const {
+ return *extendee_;
+}
+inline void FieldDescriptorProto::set_extendee(const ::std::string& value) {
+ _set_bit(5);
+ if (extendee_ == &_default_extendee_) {
+ extendee_ = new ::std::string;
+ }
+ extendee_->assign(value);
+}
+inline void FieldDescriptorProto::set_extendee(const char* value) {
+ _set_bit(5);
+ if (extendee_ == &_default_extendee_) {
+ extendee_ = new ::std::string;
+ }
+ extendee_->assign(value);
+}
+inline ::std::string* FieldDescriptorProto::mutable_extendee() {
+ _set_bit(5);
+ if (extendee_ == &_default_extendee_) {
+ extendee_ = new ::std::string;
+ }
+ return extendee_;
+}
+
+// optional string default_value = 7;
+inline bool FieldDescriptorProto::has_default_value() const {
+ return _has_bit(6);
+}
+inline void FieldDescriptorProto::clear_default_value() {
+ if (default_value_ != &_default_default_value_) {
+ default_value_->clear();
+ }
+ _clear_bit(6);
+}
+inline const ::std::string& FieldDescriptorProto::default_value() const {
+ return *default_value_;
+}
+inline void FieldDescriptorProto::set_default_value(const ::std::string& value) {
+ _set_bit(6);
+ if (default_value_ == &_default_default_value_) {
+ default_value_ = new ::std::string;
+ }
+ default_value_->assign(value);
+}
+inline void FieldDescriptorProto::set_default_value(const char* value) {
+ _set_bit(6);
+ if (default_value_ == &_default_default_value_) {
+ default_value_ = new ::std::string;
+ }
+ default_value_->assign(value);
+}
+inline ::std::string* FieldDescriptorProto::mutable_default_value() {
+ _set_bit(6);
+ if (default_value_ == &_default_default_value_) {
+ default_value_ = new ::std::string;
+ }
+ return default_value_;
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+inline bool FieldDescriptorProto::has_options() const {
+ return _has_bit(7);
+}
+inline void FieldDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+ _clear_bit(7);
+}
+inline const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
+ _set_bit(7);
+ if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumDescriptorProto
+
+// optional string name = 1;
+inline bool EnumDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void EnumDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& EnumDescriptorProto::name() const {
+ return *name_;
+}
+inline void EnumDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void EnumDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* EnumDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+inline int EnumDescriptorProto::value_size() const {
+ return value_.size();
+}
+inline void EnumDescriptorProto::clear_value() {
+ value_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+ return value_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+EnumDescriptorProto::mutable_value() {
+ return &value_;
+}
+inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+ return value_.Get(index);
+}
+inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+ return value_.Mutable(index);
+}
+inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+ return value_.Add();
+}
+
+// optional .google.protobuf.EnumOptions options = 3;
+inline bool EnumDescriptorProto::has_options() const {
+ return _has_bit(2);
+}
+inline void EnumDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
+ _clear_bit(2);
+}
+inline const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
+ _set_bit(2);
+ if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumValueDescriptorProto
+
+// optional string name = 1;
+inline bool EnumValueDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void EnumValueDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& EnumValueDescriptorProto::name() const {
+ return *name_;
+}
+inline void EnumValueDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void EnumValueDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* EnumValueDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// optional int32 number = 2;
+inline bool EnumValueDescriptorProto::has_number() const {
+ return _has_bit(1);
+}
+inline void EnumValueDescriptorProto::clear_number() {
+ number_ = 0;
+ _clear_bit(1);
+}
+inline ::google::protobuf::int32 EnumValueDescriptorProto::number() const {
+ return number_;
+}
+inline void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) {
+ _set_bit(1);
+ number_ = value;
+}
+
+// optional .google.protobuf.EnumValueOptions options = 3;
+inline bool EnumValueDescriptorProto::has_options() const {
+ return _has_bit(2);
+}
+inline void EnumValueDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
+ _clear_bit(2);
+}
+inline const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
+ _set_bit(2);
+ if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// ServiceDescriptorProto
+
+// optional string name = 1;
+inline bool ServiceDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void ServiceDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& ServiceDescriptorProto::name() const {
+ return *name_;
+}
+inline void ServiceDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void ServiceDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* ServiceDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// repeated .google.protobuf.MethodDescriptorProto method = 2;
+inline int ServiceDescriptorProto::method_size() const {
+ return method_.size();
+}
+inline void ServiceDescriptorProto::clear_method() {
+ method_.Clear();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+ return method_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+ServiceDescriptorProto::mutable_method() {
+ return &method_;
+}
+inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+ return method_.Get(index);
+}
+inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+ return method_.Mutable(index);
+}
+inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+ return method_.Add();
+}
+
+// optional .google.protobuf.ServiceOptions options = 3;
+inline bool ServiceDescriptorProto::has_options() const {
+ return _has_bit(2);
+}
+inline void ServiceDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
+ _clear_bit(2);
+}
+inline const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
+ _set_bit(2);
+ if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// MethodDescriptorProto
+
+// optional string name = 1;
+inline bool MethodDescriptorProto::has_name() const {
+ return _has_bit(0);
+}
+inline void MethodDescriptorProto::clear_name() {
+ if (name_ != &_default_name_) {
+ name_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& MethodDescriptorProto::name() const {
+ return *name_;
+}
+inline void MethodDescriptorProto::set_name(const ::std::string& value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline void MethodDescriptorProto::set_name(const char* value) {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ name_->assign(value);
+}
+inline ::std::string* MethodDescriptorProto::mutable_name() {
+ _set_bit(0);
+ if (name_ == &_default_name_) {
+ name_ = new ::std::string;
+ }
+ return name_;
+}
+
+// optional string input_type = 2;
+inline bool MethodDescriptorProto::has_input_type() const {
+ return _has_bit(1);
+}
+inline void MethodDescriptorProto::clear_input_type() {
+ if (input_type_ != &_default_input_type_) {
+ input_type_->clear();
+ }
+ _clear_bit(1);
+}
+inline const ::std::string& MethodDescriptorProto::input_type() const {
+ return *input_type_;
+}
+inline void MethodDescriptorProto::set_input_type(const ::std::string& value) {
+ _set_bit(1);
+ if (input_type_ == &_default_input_type_) {
+ input_type_ = new ::std::string;
+ }
+ input_type_->assign(value);
+}
+inline void MethodDescriptorProto::set_input_type(const char* value) {
+ _set_bit(1);
+ if (input_type_ == &_default_input_type_) {
+ input_type_ = new ::std::string;
+ }
+ input_type_->assign(value);
+}
+inline ::std::string* MethodDescriptorProto::mutable_input_type() {
+ _set_bit(1);
+ if (input_type_ == &_default_input_type_) {
+ input_type_ = new ::std::string;
+ }
+ return input_type_;
+}
+
+// optional string output_type = 3;
+inline bool MethodDescriptorProto::has_output_type() const {
+ return _has_bit(2);
+}
+inline void MethodDescriptorProto::clear_output_type() {
+ if (output_type_ != &_default_output_type_) {
+ output_type_->clear();
+ }
+ _clear_bit(2);
+}
+inline const ::std::string& MethodDescriptorProto::output_type() const {
+ return *output_type_;
+}
+inline void MethodDescriptorProto::set_output_type(const ::std::string& value) {
+ _set_bit(2);
+ if (output_type_ == &_default_output_type_) {
+ output_type_ = new ::std::string;
+ }
+ output_type_->assign(value);
+}
+inline void MethodDescriptorProto::set_output_type(const char* value) {
+ _set_bit(2);
+ if (output_type_ == &_default_output_type_) {
+ output_type_ = new ::std::string;
+ }
+ output_type_->assign(value);
+}
+inline ::std::string* MethodDescriptorProto::mutable_output_type() {
+ _set_bit(2);
+ if (output_type_ == &_default_output_type_) {
+ output_type_ = new ::std::string;
+ }
+ return output_type_;
+}
+
+// optional .google.protobuf.MethodOptions options = 4;
+inline bool MethodDescriptorProto::has_options() const {
+ return _has_bit(3);
+}
+inline void MethodDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
+ _clear_bit(3);
+}
+inline const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const {
+ return options_ != NULL ? *options_ : *default_instance_.options_;
+}
+inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
+ _set_bit(3);
+ if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions;
+ return options_;
+}
+
+// -------------------------------------------------------------------
+
+// FileOptions
+
+// optional string java_package = 1;
+inline bool FileOptions::has_java_package() const {
+ return _has_bit(0);
+}
+inline void FileOptions::clear_java_package() {
+ if (java_package_ != &_default_java_package_) {
+ java_package_->clear();
+ }
+ _clear_bit(0);
+}
+inline const ::std::string& FileOptions::java_package() const {
+ return *java_package_;
+}
+inline void FileOptions::set_java_package(const ::std::string& value) {
+ _set_bit(0);
+ if (java_package_ == &_default_java_package_) {
+ java_package_ = new ::std::string;
+ }
+ java_package_->assign(value);
+}
+inline void FileOptions::set_java_package(const char* value) {
+ _set_bit(0);
+ if (java_package_ == &_default_java_package_) {
+ java_package_ = new ::std::string;
+ }
+ java_package_->assign(value);
+}
+inline ::std::string* FileOptions::mutable_java_package() {
+ _set_bit(0);
+ if (java_package_ == &_default_java_package_) {
+ java_package_ = new ::std::string;
+ }
+ return java_package_;
+}
+
+// optional string java_outer_classname = 8;
+inline bool FileOptions::has_java_outer_classname() const {
+ return _has_bit(1);
+}
+inline void FileOptions::clear_java_outer_classname() {
+ if (java_outer_classname_ != &_default_java_outer_classname_) {
+ java_outer_classname_->clear();
+ }
+ _clear_bit(1);
+}
+inline const ::std::string& FileOptions::java_outer_classname() const {
+ return *java_outer_classname_;
+}
+inline void FileOptions::set_java_outer_classname(const ::std::string& value) {
+ _set_bit(1);
+ if (java_outer_classname_ == &_default_java_outer_classname_) {
+ java_outer_classname_ = new ::std::string;
+ }
+ java_outer_classname_->assign(value);
+}
+inline void FileOptions::set_java_outer_classname(const char* value) {
+ _set_bit(1);
+ if (java_outer_classname_ == &_default_java_outer_classname_) {
+ java_outer_classname_ = new ::std::string;
+ }
+ java_outer_classname_->assign(value);
+}
+inline ::std::string* FileOptions::mutable_java_outer_classname() {
+ _set_bit(1);
+ if (java_outer_classname_ == &_default_java_outer_classname_) {
+ java_outer_classname_ = new ::std::string;
+ }
+ return java_outer_classname_;
+}
+
+// optional bool java_multiple_files = 10 [default = false];
+inline bool FileOptions::has_java_multiple_files() const {
+ return _has_bit(2);
+}
+inline void FileOptions::clear_java_multiple_files() {
+ java_multiple_files_ = false;
+ _clear_bit(2);
+}
+inline bool FileOptions::java_multiple_files() const {
+ return java_multiple_files_;
+}
+inline void FileOptions::set_java_multiple_files(bool value) {
+ _set_bit(2);
+ java_multiple_files_ = value;
+}
+
+// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE];
+inline bool FileOptions::has_optimize_for() const {
+ return _has_bit(3);
+}
+inline void FileOptions::clear_optimize_for() {
+ optimize_for_ = 2;
+ _clear_bit(3);
+}
+inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+ return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_);
+}
+inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) {
+ GOOGLE_DCHECK(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
+ _set_bit(3);
+ optimize_for_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// MessageOptions
+
+// optional bool message_set_wire_format = 1 [default = false];
+inline bool MessageOptions::has_message_set_wire_format() const {
+ return _has_bit(0);
+}
+inline void MessageOptions::clear_message_set_wire_format() {
+ message_set_wire_format_ = false;
+ _clear_bit(0);
+}
+inline bool MessageOptions::message_set_wire_format() const {
+ return message_set_wire_format_;
+}
+inline void MessageOptions::set_message_set_wire_format(bool value) {
+ _set_bit(0);
+ message_set_wire_format_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// FieldOptions
+
+// optional .google.protobuf.FieldOptions.CType ctype = 1;
+inline bool FieldOptions::has_ctype() const {
+ return _has_bit(0);
+}
+inline void FieldOptions::clear_ctype() {
+ ctype_ = 1;
+ _clear_bit(0);
+}
+inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const {
+ return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_);
+}
+inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) {
+ GOOGLE_DCHECK(::google::protobuf::FieldOptions_CType_IsValid(value));
+ _set_bit(0);
+ ctype_ = value;
+}
+
+// optional string experimental_map_key = 9;
+inline bool FieldOptions::has_experimental_map_key() const {
+ return _has_bit(1);
+}
+inline void FieldOptions::clear_experimental_map_key() {
+ if (experimental_map_key_ != &_default_experimental_map_key_) {
+ experimental_map_key_->clear();
+ }
+ _clear_bit(1);
+}
+inline const ::std::string& FieldOptions::experimental_map_key() const {
+ return *experimental_map_key_;
+}
+inline void FieldOptions::set_experimental_map_key(const ::std::string& value) {
+ _set_bit(1);
+ if (experimental_map_key_ == &_default_experimental_map_key_) {
+ experimental_map_key_ = new ::std::string;
+ }
+ experimental_map_key_->assign(value);
+}
+inline void FieldOptions::set_experimental_map_key(const char* value) {
+ _set_bit(1);
+ if (experimental_map_key_ == &_default_experimental_map_key_) {
+ experimental_map_key_ = new ::std::string;
+ }
+ experimental_map_key_->assign(value);
+}
+inline ::std::string* FieldOptions::mutable_experimental_map_key() {
+ _set_bit(1);
+ if (experimental_map_key_ == &_default_experimental_map_key_) {
+ experimental_map_key_ = new ::std::string;
+ }
+ return experimental_map_key_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumOptions
+
+// -------------------------------------------------------------------
+
+// EnumValueOptions
+
+// -------------------------------------------------------------------
+
+// ServiceOptions
+
+// -------------------------------------------------------------------
+
+// MethodOptions
+
+
+} // namespace protobuf
+} // namespace google
+#endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
new file mode 100644
index 00000000..13d94780
--- /dev/null
+++ b/src/google/protobuf/descriptor.proto
@@ -0,0 +1,286 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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).
+
+
+
+package google.protobuf;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// 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;
+
+ // 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;
+}
+
+// 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;
+ optional int32 end = 2;
+ }
+ repeated ExtensionRange extension_range = 5;
+
+ optional MessageOptions options = 7;
+}
+
+// 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;
+ TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
+ // take 10 bytes. Use TYPE_SINT64 if negative
+ // values are likely.
+ TYPE_UINT64 = 4;
+ TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
+ // take 10 bytes. Use TYPE_SINT32 if negative
+ // values are likely.
+ TYPE_FIXED64 = 6;
+ TYPE_FIXED32 = 7;
+ TYPE_BOOL = 8;
+ TYPE_STRING = 9;
+ TYPE_GROUP = 10; // Tag-delimited aggregate.
+ 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;
+ // TODO(sanjay): Should we add LABEL_MAP?
+ };
+
+ 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 either TYPE_ENUM or TYPE_MESSAGE.
+ 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.
+ // TODO(kenton): Base-64 encode?
+ optional string default_value = 7;
+
+ optional FieldOptions options = 8;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+ optional string name = 1;
+
+ repeated EnumValueDescriptorProto value = 2;
+
+ optional EnumOptions options = 3;
+}
+
+// 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;
+}
+
+// ===================================================================
+// 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.
+
+// TODO(kenton): Allow extensions to options.
+
+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;
+
+
+ // If set, all the classes from the .proto file are wrapped in a single
+ // outer class with the given name. This applies to both Proto1
+ // (equivalent to the old "--one_java_file" option) and Proto2 (where
+ // a .proto always translates to a single class, but you may want to
+ // explicitly choose the class name).
+ optional string java_outer_classname = 8;
+
+ // If set true, then the Java code generator will generate a separate .java
+ // file for each top-level message, enum, and service defined in the .proto
+ // file. Thus, these types will *not* be nested inside the outer class
+ // named by java_outer_classname. However, the outer class will still be
+ // generated to contain the file's getDescriptor() method as well as any
+ // top-level extensions defined in the file.
+ optional bool java_multiple_files = 10 [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.
+ }
+ optional OptimizeMode optimize_for = 9 [default=CODE_SIZE];
+}
+
+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];
+}
+
+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;
+ enum CType {
+ CORD = 1;
+
+ STRING_PIECE = 2;
+ }
+
+ // EXPERIMENTAL. DO NOT USE.
+ // For "map" fields, the name of the field in the enclosed type that
+ // is the key for this map. For example, suppose we have:
+ // message Item {
+ // required string name = 1;
+ // required string value = 2;
+ // }
+ // message Config {
+ // repeated Item items = 1 [experimental_map_key="name"];
+ // }
+ // In this situation, the map key for Item will be set to "name".
+ // TODO: Fully-implement this, then remove the "experimental_" prefix.
+ optional string experimental_map_key = 9;
+}
+
+message EnumOptions {
+}
+
+message EnumValueOptions {
+}
+
+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.
+}
+
+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.
+}
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
new file mode 100644
index 00000000..944280c0
--- /dev/null
+++ b/src/google/protobuf/descriptor_database.cc
@@ -0,0 +1,291 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/map-util.h>
+
+namespace google {
+namespace protobuf {
+
+DescriptorDatabase::~DescriptorDatabase() {}
+
+// ===================================================================
+
+SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
+SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
+ STLDeleteElements(&files_to_delete_);
+}
+
+void SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
+ FileDescriptorProto* new_file = new FileDescriptorProto;
+ new_file->CopyFrom(file);
+ AddAndOwn(new_file);
+}
+
+void SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
+ files_to_delete_.push_back(file);
+ InsertOrUpdate(&files_by_name_, file->name(), file);
+
+ string path = file->package();
+ if (!path.empty()) path += '.';
+
+ for (int i = 0; i < file->message_type_size(); i++) {
+ AddMessage(path, file->message_type(i), file);
+ }
+ for (int i = 0; i < file->enum_type_size(); i++) {
+ AddEnum(path, file->enum_type(i), file);
+ }
+ for (int i = 0; i < file->extension_size(); i++) {
+ AddField(path, file->extension(i), file);
+ }
+ for (int i = 0; i < file->service_size(); i++) {
+ AddService(path, file->service(i), file);
+ }
+}
+
+void SimpleDescriptorDatabase::AddMessage(
+ const string& path,
+ const DescriptorProto& message_type,
+ const FileDescriptorProto* file) {
+ string full_name = path + message_type.name();
+ InsertOrUpdate(&files_by_symbol_, full_name, file);
+
+ string sub_path = full_name + '.';
+ for (int i = 0; i < message_type.nested_type_size(); i++) {
+ AddMessage(sub_path, message_type.nested_type(i), file);
+ }
+ for (int i = 0; i < message_type.enum_type_size(); i++) {
+ AddEnum(sub_path, message_type.enum_type(i), file);
+ }
+ for (int i = 0; i < message_type.field_size(); i++) {
+ AddField(sub_path, message_type.field(i), file);
+ }
+ for (int i = 0; i < message_type.extension_size(); i++) {
+ AddField(sub_path, message_type.extension(i), file);
+ }
+}
+
+void SimpleDescriptorDatabase::AddField(
+ const string& path,
+ const FieldDescriptorProto& field,
+ const FileDescriptorProto* file) {
+ string full_name = path + field.name();
+ InsertOrUpdate(&files_by_symbol_, full_name, file);
+
+ if (field.has_extendee()) {
+ // This field is an extension.
+ if (!field.extendee().empty() && field.extendee()[0] == '.') {
+ // The extension is fully-qualified. We can use it as a lookup key in
+ // the files_by_symbol_ table.
+ InsertOrUpdate(&files_by_extension_,
+ make_pair(field.extendee().substr(1), field.number()),
+ file);
+ } else {
+ // Not fully-qualified. We can't really do anything here, unfortunately.
+ }
+ }
+}
+
+void SimpleDescriptorDatabase::AddEnum(
+ const string& path,
+ const EnumDescriptorProto& enum_type,
+ const FileDescriptorProto* file) {
+ string full_name = path + enum_type.name();
+ InsertOrUpdate(&files_by_symbol_, full_name, file);
+
+ string sub_path = full_name + '.';
+ for (int i = 0; i < enum_type.value_size(); i++) {
+ InsertOrUpdate(&files_by_symbol_,
+ sub_path + enum_type.value(i).name(),
+ file);
+ }
+}
+
+void SimpleDescriptorDatabase::AddService(
+ const string& path,
+ const ServiceDescriptorProto& service,
+ const FileDescriptorProto* file) {
+ string full_name = path + service.name();
+ InsertOrUpdate(&files_by_symbol_, full_name, file);
+
+ string sub_path = full_name + '.';
+ for (int i = 0; i < service.method_size(); i++) {
+ InsertOrUpdate(&files_by_symbol_,
+ sub_path + service.method(i).name(),
+ file);
+ }
+}
+
+bool SimpleDescriptorDatabase::FindFileByName(
+ const string& filename,
+ FileDescriptorProto* output) {
+ const FileDescriptorProto* result = FindPtrOrNull(files_by_name_, filename);
+ if (result == NULL) {
+ return false;
+ } else {
+ output->CopyFrom(*result);
+ return true;
+ }
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingSymbol(
+ const string& symbol_name,
+ FileDescriptorProto* output) {
+ const FileDescriptorProto* result =
+ FindPtrOrNull(files_by_symbol_, symbol_name);
+ if (result == NULL) {
+ return false;
+ } else {
+ output->CopyFrom(*result);
+ return true;
+ }
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingExtension(
+ const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ const FileDescriptorProto* result =
+ FindPtrOrNull(files_by_extension_,
+ make_pair(containing_type, field_number));
+ if (result == NULL) {
+ return false;
+ } else {
+ output->CopyFrom(*result);
+ return true;
+ }
+}
+
+// ===================================================================
+
+DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
+ : pool_(pool) {}
+DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
+
+bool DescriptorPoolDatabase::FindFileByName(
+ const string& filename,
+ FileDescriptorProto* output) {
+ const FileDescriptor* file = pool_.FindFileByName(filename);
+ if (file == NULL) return false;
+ output->Clear();
+ file->CopyTo(output);
+ return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingSymbol(
+ const string& symbol_name,
+ FileDescriptorProto* output) {
+ const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
+ if (file == NULL) return false;
+ output->Clear();
+ file->CopyTo(output);
+ return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingExtension(
+ const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
+ if (extendee == NULL) return false;
+
+ const FieldDescriptor* extension =
+ pool_.FindExtensionByNumber(extendee, field_number);
+ if (extension == NULL) return false;
+
+ output->Clear();
+ extension->file()->CopyTo(output);
+ return true;
+}
+
+// ===================================================================
+
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+ DescriptorDatabase* source1,
+ DescriptorDatabase* source2) {
+ sources_.push_back(source1);
+ sources_.push_back(source2);
+}
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+ const vector<DescriptorDatabase*>& sources)
+ : sources_(sources) {}
+MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
+
+bool MergedDescriptorDatabase::FindFileByName(
+ const string& filename,
+ FileDescriptorProto* output) {
+ for (int i = 0; i < sources_.size(); i++) {
+ if (sources_[i]->FindFileByName(filename, output)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MergedDescriptorDatabase::FindFileContainingSymbol(
+ const string& symbol_name,
+ FileDescriptorProto* output) {
+ for (int 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 (int 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 string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ for (int 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 (int 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;
+}
+
+} // 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 00000000..d629da4c
--- /dev/null
+++ b/src/google/protobuf/descriptor_database.h
@@ -0,0 +1,183 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+// 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 LIBPROTOBUF_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 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 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 string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) = 0;
+
+ 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.
+//
+// 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 LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
+ public:
+ SimpleDescriptorDatabase();
+ ~SimpleDescriptorDatabase();
+
+ // Adds the FileDescriptorProto to the database, making a copy. The object
+ // can be deleted after Add() returns.
+ void Add(const FileDescriptorProto& file);
+
+ // Adds the FileDescriptorProto to the database and takes ownership of it.
+ void AddAndOwn(const FileDescriptorProto* file);
+
+ // implements DescriptorDatabase -----------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output);
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output);
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output);
+
+ private:
+ // Helpers to recursively add particular descriptors and all their contents
+ // to the by-symbol and by-extension tables.
+ void AddMessage(const string& path,
+ const DescriptorProto& message_type,
+ const FileDescriptorProto* file);
+ void AddField(const string& path,
+ const FieldDescriptorProto& field,
+ const FileDescriptorProto* file);
+ void AddEnum(const string& path,
+ const EnumDescriptorProto& enum_type,
+ const FileDescriptorProto* file);
+ void AddService(const string& path,
+ const ServiceDescriptorProto& service,
+ const FileDescriptorProto* file);
+
+ vector<const FileDescriptorProto*> files_to_delete_;
+ map<string, const FileDescriptorProto*> files_by_name_;
+ map<string, const FileDescriptorProto*> files_by_symbol_;
+ map<pair<string, int>, const FileDescriptorProto*> files_by_extension_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
+};
+
+// A DescriptorDatabase that fetches files from a given pool.
+class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
+ public:
+ DescriptorPoolDatabase(const DescriptorPool& pool);
+ ~DescriptorPoolDatabase();
+
+ // implements DescriptorDatabase -----------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output);
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output);
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output);
+
+ 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 LIBPROTOBUF_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.
+ MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
+ ~MergedDescriptorDatabase();
+
+ // implements DescriptorDatabase -----------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output);
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output);
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output);
+
+ private:
+ vector<DescriptorDatabase*> sources_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..cbbf5927
--- /dev/null
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -0,0 +1,601 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+static bool AddToPool(DescriptorPool* pool, const char* file_text) {
+ FileDescriptorProto file_proto;
+ if (!TextFormat::ParseFromString(file_text, &file_proto)) return false;
+ if (pool->BuildFile(file_proto) == NULL) return false;
+ return true;
+}
+
+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 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 << "\".";
+}
+
+// ===================================================================
+
+TEST(SimpleDescriptorDatabaseTest, FindFileByName) {
+ SimpleDescriptorDatabase database;
+ AddToDatabase(&database,
+ "name: \"foo.proto\" "
+ "message_type { name:\"Foo\" }");
+ AddToDatabase(&database,
+ "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(SimpleDescriptorDatabaseTest, FindFileContainingSymbol) {
+ SimpleDescriptorDatabase database;
+ AddToDatabase(&database,
+ "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(&database,
+ "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());
+ }
+
+ {
+ // 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(SimpleDescriptorDatabaseTest, FindFileContainingExtension) {
+ SimpleDescriptorDatabase database;
+ AddToDatabase(&database,
+ "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(&database,
+ "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(DescriptorPoolDatabaseTest, FindFileByName) {
+ DescriptorPool pool;
+ ASSERT_TRUE(AddToPool(&pool,
+ "name: \"foo.proto\" "
+ "message_type { name:\"Foo\" }"));
+ ASSERT_TRUE(AddToPool(&pool,
+ "name: \"bar.proto\" "
+ "message_type { name:\"Bar\" }"));
+
+ DescriptorPoolDatabase database(pool);
+
+ {
+ 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(DescriptorPoolDatabaseTest, FindFileContainingSymbol) {
+ DescriptorPool pool;
+ ASSERT_TRUE(AddToPool(&pool,
+ "name: \"foo.proto\" "
+ "message_type { "
+ " name: \"Foo\" "
+ " field { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
+ "}"));
+ ASSERT_TRUE(AddToPool(&pool,
+ "name: \"bar.proto\" "
+ "package: \"corge\" "
+ "message_type { name: \"Bar\" }"));
+
+ DescriptorPoolDatabase database(pool);
+
+ {
+ 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());
+ }
+
+ {
+ // 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(DescriptorPoolDatabaseTest, FindFileContainingExtension) {
+ DescriptorPool pool;
+ ASSERT_TRUE(AddToPool(&pool,
+ "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\" }"
+ "}"));
+ ASSERT_TRUE(AddToPool(&pool,
+ "name: \"bar.proto\" "
+ "package: \"corge\" "
+ "dependency: \"foo.proto\" "
+ "message_type { "
+ " name: \"Bar\" "
+ " extension_range { start: 1 end: 1000 } "
+ "} "
+ "extension { name:\"grault\" label:LABEL_OPTIONAL type:TYPE_BOOL number:32 "
+ " extendee: \"Foo\" } "
+ "extension { name:\"garply\" label:LABEL_OPTIONAL type:TYPE_BOOL number:70 "
+ " extendee: \"Bar\" } "));
+
+ DescriptorPoolDatabase database(pool);
+
+ {
+ 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 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));
+ }
+}
+
+// ===================================================================
+
+class MergedDescriptorDatabaseTest : public testing::Test {
+ protected:
+ MergedDescriptorDatabaseTest()
+ : forward_merged_(&database1_, &database2_),
+ reverse_merged_(&database2_, &database1_) {}
+
+ virtual void SetUp() {
+ 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));
+ }
+}
+
+} // 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 00000000..18397a66
--- /dev/null
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -0,0 +1,2634 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <vector>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+// Some helpers to make assembling descriptors faster.
+DescriptorProto* AddMessage(FileDescriptorProto* file, const string& name) {
+ DescriptorProto* result = file->add_message_type();
+ result->set_name(name);
+ return result;
+}
+
+DescriptorProto* AddNestedMessage(DescriptorProto* parent, const string& name) {
+ DescriptorProto* result = parent->add_nested_type();
+ result->set_name(name);
+ return result;
+}
+
+EnumDescriptorProto* AddEnum(FileDescriptorProto* file, const string& name) {
+ EnumDescriptorProto* result = file->add_enum_type();
+ result->set_name(name);
+ return result;
+}
+
+EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent,
+ const string& name) {
+ EnumDescriptorProto* result = parent->add_enum_type();
+ result->set_name(name);
+ return result;
+}
+
+ServiceDescriptorProto* AddService(FileDescriptorProto* file,
+ const string& name) {
+ ServiceDescriptorProto* result = file->add_service();
+ result->set_name(name);
+ return result;
+}
+
+FieldDescriptorProto* AddField(DescriptorProto* parent,
+ const 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 string& extendee,
+ const 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 string& extendee,
+ const 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;
+}
+
+EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
+ const 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 string& name,
+ const string& input_type,
+ const 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 string& name) {
+ AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
+}
+
+// ===================================================================
+
+// Test simple files.
+class FileDescriptorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // 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_ != NULL);
+
+ bar_file_ = pool_.BuildFile(bar_file);
+ ASSERT_TRUE(bar_file_ != NULL);
+
+ baz_file_ = pool_.BuildFile(baz_file);
+ ASSERT_TRUE(baz_file_ != NULL);
+
+ 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") == NULL);
+ EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == NULL);
+ EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == NULL);
+
+ EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == NULL);
+ EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == NULL);
+ EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == NULL);
+
+ EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == NULL);
+ EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL);
+ EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL);
+
+ EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == NULL);
+ EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == NULL);
+
+ EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == NULL);
+ EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == NULL);
+ EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == NULL);
+
+ EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == NULL);
+ EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == NULL);
+}
+
+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) == NULL);
+}
+
+// ===================================================================
+
+// Test simple flat messages and fields.
+class DescriptorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // 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 qux = 15 {}
+ // }
+ //
+ // // in "bar.proto"
+ // package corge.grault;
+ // message TestMessage2 {
+ // required string foo = 1;
+ // required string bar = 2;
+ // required string quux = 6;
+ // }
+ //
+ // We cheat and use TestForeign as the type for qux 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, "qux", 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, "quux", 6,
+ FieldDescriptorProto::LABEL_REQUIRED,
+ FieldDescriptorProto::TYPE_STRING);
+
+ // Build the descriptors and get the pointers.
+ foo_file_ = pool_.BuildFile(foo_file);
+ ASSERT_TRUE(foo_file_ != NULL);
+
+ bar_file_ = pool_.BuildFile(bar_file);
+ ASSERT_TRUE(bar_file_ != NULL);
+
+ 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);
+ qux_ = 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);
+ quux2_ = message2_->field(2);
+ }
+
+ DescriptorPool pool_;
+
+ const FileDescriptor* foo_file_;
+ const FileDescriptor* bar_file_;
+
+ const Descriptor* message_;
+ const Descriptor* message2_;
+ const Descriptor* foreign_;
+ const EnumDescriptor* enum_;
+
+ const FieldDescriptor* foo_;
+ const FieldDescriptor* bar_;
+ const FieldDescriptor* baz_;
+ const FieldDescriptor* qux_;
+
+ const FieldDescriptor* foo2_;
+ const FieldDescriptor* bar2_;
+ const FieldDescriptor* quux2_;
+};
+
+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() == NULL);
+ EXPECT_TRUE(message2_->containing_type() == NULL);
+}
+
+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(qux_, 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(qux_, message_->FindFieldByName("qux"));
+ EXPECT_TRUE(message_->FindFieldByName("no_such_field") == NULL);
+ EXPECT_TRUE(message_->FindFieldByName("quux") == NULL);
+
+ EXPECT_EQ(foo2_ , message2_->FindFieldByName("foo" ));
+ EXPECT_EQ(bar2_ , message2_->FindFieldByName("bar" ));
+ EXPECT_EQ(quux2_, message2_->FindFieldByName("quux"));
+ EXPECT_TRUE(message2_->FindFieldByName("baz") == NULL);
+ EXPECT_TRUE(message2_->FindFieldByName("qux") == NULL);
+}
+
+TEST_F(DescriptorTest, FindFieldByNumber) {
+ EXPECT_EQ(foo_, message_->FindFieldByNumber(1));
+ EXPECT_EQ(bar_, message_->FindFieldByNumber(6));
+ EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000));
+ EXPECT_EQ(qux_, message_->FindFieldByNumber(15));
+ EXPECT_TRUE(message_->FindFieldByNumber(837592) == NULL);
+ EXPECT_TRUE(message_->FindFieldByNumber(2) == NULL);
+
+ EXPECT_EQ(foo2_ , message2_->FindFieldByNumber(1));
+ EXPECT_EQ(bar2_ , message2_->FindFieldByNumber(2));
+ EXPECT_EQ(quux2_, message2_->FindFieldByNumber(6));
+ EXPECT_TRUE(message2_->FindFieldByNumber(15) == NULL);
+ EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == NULL);
+}
+
+TEST_F(DescriptorTest, FieldName) {
+ EXPECT_EQ("foo", foo_->name());
+ EXPECT_EQ("bar", bar_->name());
+ EXPECT_EQ("baz", baz_->name());
+ EXPECT_EQ("qux", qux_->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.qux", qux_->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.quux", quux2_->full_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_, qux_->file());
+
+ EXPECT_EQ(bar_file_, foo2_->file());
+ EXPECT_EQ(bar_file_, bar2_->file());
+ EXPECT_EQ(bar_file_, quux2_->file());
+}
+
+TEST_F(DescriptorTest, FieldIndex) {
+ EXPECT_EQ(0, foo_->index());
+ EXPECT_EQ(1, bar_->index());
+ EXPECT_EQ(2, baz_->index());
+ EXPECT_EQ(3, qux_->index());
+}
+
+TEST_F(DescriptorTest, FieldNumber) {
+ EXPECT_EQ( 1, foo_->number());
+ EXPECT_EQ( 6, bar_->number());
+ EXPECT_EQ(500000000, baz_->number());
+ EXPECT_EQ( 15, qux_->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 , qux_->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, qux_->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, FieldHasDefault) {
+ EXPECT_FALSE(foo_->has_default_value());
+ EXPECT_FALSE(bar_->has_default_value());
+ EXPECT_FALSE(baz_->has_default_value());
+ EXPECT_FALSE(qux_->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_, qux_->containing_type());
+
+ EXPECT_EQ(message2_, foo2_ ->containing_type());
+ EXPECT_EQ(message2_, bar2_ ->containing_type());
+ EXPECT_EQ(message2_, quux2_->containing_type());
+}
+
+TEST_F(DescriptorTest, FieldMessageType) {
+ EXPECT_TRUE(foo_->message_type() == NULL);
+ EXPECT_TRUE(bar_->message_type() == NULL);
+
+ EXPECT_EQ(foreign_, baz_->message_type());
+ EXPECT_EQ(foreign_, qux_->message_type());
+}
+
+TEST_F(DescriptorTest, FieldEnumType) {
+ EXPECT_TRUE(foo_->enum_type() == NULL);
+ EXPECT_TRUE(baz_->enum_type() == NULL);
+ EXPECT_TRUE(qux_->enum_type() == NULL);
+
+ EXPECT_EQ(enum_, bar_->enum_type());
+}
+
+// ===================================================================
+
+// Test enum descriptors.
+class EnumDescriptorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // 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_ != NULL);
+
+ bar_file_ = pool_.BuildFile(bar_file);
+ ASSERT_TRUE(bar_file_ != NULL);
+
+ 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() == NULL);
+ EXPECT_TRUE(enum2_->containing_type() == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(enum_ ->FindValueByName("BAZ" ) == NULL);
+ EXPECT_TRUE(enum2_->FindValueByName("BAR" ) == NULL);
+}
+
+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) == NULL);
+ EXPECT_TRUE(enum_ ->FindValueByNumber(3) == NULL);
+ EXPECT_TRUE(enum2_->FindValueByNumber(2) == NULL);
+}
+
+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:
+ virtual void SetUp() {
+ // 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_ != NULL);
+
+ bar_file_ = pool_.BuildFile(bar_file);
+ ASSERT_TRUE(bar_file_ != NULL);
+
+ 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") == NULL);
+ EXPECT_TRUE(service_ ->FindMethodByName("Baz" ) == NULL);
+ EXPECT_TRUE(service2_->FindMethodByName("Bar" ) == NULL);
+}
+
+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:
+ virtual void SetUp() {
+ // Build descriptors for the following definitions:
+ //
+ // // in "foo.proto"
+ // message TestMessage {
+ // message Foo {}
+ // message Bar {}
+ // enum Baz { A = 1; }
+ // enum Qux { B = 1; }
+ // }
+ //
+ // // in "bar.proto"
+ // package corge.grault;
+ // message TestMessage2 {
+ // message Foo {}
+ // message Baz {}
+ // enum Qux { A = 1; }
+ // enum Quux { 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* qux = AddNestedEnum(message, "Qux");
+ AddEnumValue(qux, "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* qux2 = AddNestedEnum(message2, "Qux");
+ AddEnumValue(qux2, "A", 1);
+ EnumDescriptorProto* quux2 = AddNestedEnum(message2, "Quux");
+ AddEnumValue(quux2, "C", 1);
+
+ // Build the descriptors and get the pointers.
+ foo_file_ = pool_.BuildFile(foo_file);
+ ASSERT_TRUE(foo_file_ != NULL);
+
+ bar_file_ = pool_.BuildFile(bar_file);
+ ASSERT_TRUE(bar_file_ != NULL);
+
+ 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);
+ qux_ = message_->enum_type(1);
+
+ ASSERT_EQ(1, baz_->value_count());
+ a_ = baz_->value(0);
+ ASSERT_EQ(1, qux_->value_count());
+ b_ = qux_->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());
+ qux2_ = message2_->enum_type(0);
+ quux2_ = message2_->enum_type(1);
+
+ ASSERT_EQ(1, qux2_->value_count());
+ a2_ = qux2_->value(0);
+ ASSERT_EQ(1, quux2_->value_count());
+ c2_ = quux2_->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* qux_;
+ const EnumValueDescriptor* a_;
+ const EnumValueDescriptor* b_;
+
+ const Descriptor* foo2_;
+ const Descriptor* baz2_;
+ const EnumDescriptor* qux2_;
+ const EnumDescriptor* quux2_;
+ 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") == NULL);
+ EXPECT_TRUE(message_->FindFieldByName("Qux") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByName("Foo") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByName("Qux") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(message_ ->FindNestedTypeByName("Baz" ) == NULL);
+ EXPECT_TRUE(message2_->FindNestedTypeByName("Bar" ) == NULL);
+
+ EXPECT_TRUE(message_->FindNestedTypeByName("Qux") == NULL);
+}
+
+TEST_F(NestedDescriptorTest, EnumName) {
+ EXPECT_EQ("Baz" , baz_ ->name());
+ EXPECT_EQ("Qux" , qux_ ->name());
+ EXPECT_EQ("Qux" , qux2_->name());
+ EXPECT_EQ("Quux", quux2_->name());
+
+ EXPECT_EQ("TestMessage.Baz", baz_->full_name());
+ EXPECT_EQ("TestMessage.Qux", qux_->full_name());
+ EXPECT_EQ("corge.grault.TestMessage2.Qux" , qux2_ ->full_name());
+ EXPECT_EQ("corge.grault.TestMessage2.Quux", quux2_->full_name());
+}
+
+TEST_F(NestedDescriptorTest, EnumContainingType) {
+ EXPECT_EQ(message_ , baz_ ->containing_type());
+ EXPECT_EQ(message_ , qux_ ->containing_type());
+ EXPECT_EQ(message2_, qux2_ ->containing_type());
+ EXPECT_EQ(message2_, quux2_->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(qux_ , message_ ->FindEnumTypeByName("Qux" ));
+ EXPECT_EQ(qux2_ , message2_->FindEnumTypeByName("Qux" ));
+ EXPECT_EQ(quux2_, message2_->FindEnumTypeByName("Quux"));
+
+ EXPECT_TRUE(message_ ->FindEnumTypeByName("NoSuchType") == NULL);
+ EXPECT_TRUE(message_ ->FindEnumTypeByName("Quux" ) == NULL);
+ EXPECT_TRUE(message2_->FindEnumTypeByName("Baz" ) == NULL);
+
+ EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == NULL);
+}
+
+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") == NULL);
+ EXPECT_TRUE(message_ ->FindEnumValueByName("C" ) == NULL);
+ EXPECT_TRUE(message2_->FindEnumValueByName("B" ) == NULL);
+
+ EXPECT_TRUE(message_->FindEnumValueByName("Foo") == NULL);
+}
+
+// ===================================================================
+
+// Test extensions.
+class ExtensionDescriptorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Build descriptors for the following definitions:
+ //
+ // enum Baz {}
+ // message Qux {}
+ //
+ // message Foo {
+ // extensions 10 to 19;
+ // extensions 30 to 39;
+ // }
+ // extends Foo with optional int32 foo_int32 = 10;
+ // extends Foo with repeated TestEnum foo_enum = 19;
+ // message Bar {
+ // extends Foo with optional Qux foo_message = 30;
+ // // (using Qux as the group type)
+ // extends Foo with repeated group foo_group = 39;
+ // }
+
+ FileDescriptorProto foo_file;
+ foo_file.set_name("foo.proto");
+
+ AddEmptyEnum(&foo_file, "Baz");
+ AddMessage(&foo_file, "Qux");
+
+ 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");
+ AddNestedExtension(bar, "Foo", "foo_message", 30,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_MESSAGE)
+ ->set_type_name("Qux");
+ AddNestedExtension(bar, "Foo", "foo_group", 39,
+ FieldDescriptorProto::LABEL_REPEATED,
+ FieldDescriptorProto::TYPE_GROUP)
+ ->set_type_name("Qux");
+
+ // Build the descriptors and get the pointers.
+ foo_file_ = pool_.BuildFile(foo_file);
+ ASSERT_TRUE(foo_file_ != NULL);
+
+ ASSERT_EQ(1, foo_file_->enum_type_count());
+ baz_ = foo_file_->enum_type(0);
+
+ ASSERT_EQ(3, foo_file_->message_type_count());
+ qux_ = 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* qux_;
+};
+
+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(qux_, bar_->extension(0)->message_type());
+ EXPECT_EQ(qux_, 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() == NULL);
+ EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == NULL);
+ 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") == NULL);
+ EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == NULL);
+ EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == NULL);
+}
+
+// ===================================================================
+
+class MiscTest : public testing::Test {
+ protected:
+ // Function which makes a field of the given type just to find out what its
+ // cpp_type is.
+ FieldDescriptor::CppType GetCppTypeForFieldType(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>(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.
+ DescriptorPool pool;
+ const FileDescriptor* file = pool.BuildFile(file_proto);
+
+ if (file != NULL &&
+ file->message_type_count() == 1 &&
+ file->message_type(0)->field_count() == 1) {
+ return file->message_type(0)->field(0)->cpp_type();
+ } else {
+ return static_cast<FieldDescriptor::CppType>(0);
+ }
+ }
+};
+
+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, 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 defalut 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 != NULL);
+
+ 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(-GOOGLE_ULONGLONG(1000000000000),
+ message->field(1)->default_value_int64 ());
+ EXPECT_EQ(42 , message->field(2)->default_value_uint32());
+ EXPECT_EQ(GOOGLE_ULONGLONG(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_EQ(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_EQ(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 != NULL);
+
+ 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());
+}
+
+// ===================================================================
+
+// The tests below trigger every unique call to AddError() in descriptor.cc,
+// in the order in which they appear in that file. I'm using TextFormat here
+// to specify the input descriptors because building them using code would
+// be too bulky.
+
+class MockErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename,
+ const string& element_name, const Message* descriptor,
+ ErrorLocation location, const string& message) {
+ const char* location_name = NULL;
+ switch (location) {
+ case NAME : location_name = "NAME" ; break;
+ case NUMBER : location_name = "NUMBER" ; break;
+ case TYPE : location_name = "TYPE" ; break;
+ case EXTENDEE : location_name = "EXTENDEE" ; break;
+ case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+ case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
+ case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
+ case OTHER : location_name = "OTHER" ; break;
+ }
+
+ strings::SubstituteAndAppend(
+ &text_, "$0: $1: $2: $3\n",
+ filename, element_name, location_name, message);
+ }
+};
+
+class ValidationErrorTest : public testing::Test {
+ protected:
+ // Parse file_text as a FileDescriptorProto in text format and add it
+ // to the DescriptorPool. Expect no errors.
+ void BuildFile(const string& file_text) {
+ FileDescriptorProto file_proto;
+ ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+ ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
+ }
+
+ // 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 string& file_text,
+ const 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) == NULL);
+ EXPECT_EQ(expected_errors, error_collector.text_);
+ }
+
+ 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, 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");
+}
+
+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: bar.proto: OTHER: Import \"foo.proto\" was listed twice.\n");
+}
+
+TEST_F(ValidationErrorTest, UnknownDependency) {
+ BuildFileWithErrors(
+ "name: \"bar.proto\" "
+ "dependency: \"foo.proto\" ",
+
+ "bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\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\" }",
+
+ "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: \"qux\" 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");
+}
+
+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, 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: \"qux\" 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: \"quux\" number: 5 label: LABEL_OPTIONAL"
+ " default_value: \"abc\" type_name: \"Foo\" }"
+ "}",
+
+ "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value.\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.qux: DEFAULT_VALUE: Messages can't have default values.\n"
+ "foo.proto: Foo.quux: 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");
+}
+
+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");
+}
+
+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:\"qux\" 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");
+}
+
+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, 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, 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, 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, SearchMostLocalFirst) {
+ // The following should produce an error that Bar.Baz is 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 not defined.\n");
+}
+
+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 qux = 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:\"qux\" 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:\"bar\" }"
+ " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+ "}",
+
+ "foo.proto: Foo.foo: TYPE: \"bar\" is not a type.\n");
+}
+
+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, 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, 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, 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));
+
+ vector<string> errors;
+
+ {
+ ScopedMemoryLog log;
+ EXPECT_TRUE(pool_.BuildFile(file_proto) == NULL);
+ 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]);
+}
+
+// ===================================================================
+// 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_;
+
+ virtual void SetUp() {
+ 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 } ");
+ }
+
+ // 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() {}
+
+ // implements DescriptorDatabase ---------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output) {
+ // 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 string& symbol_name,
+ FileDescriptorProto* output) {
+ return false;
+ }
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ 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() {}
+
+ DescriptorDatabase* wrapped_db_;
+
+ int call_count_;
+
+ void Clear() {
+ call_count_ = 0;
+ }
+
+ // implements DescriptorDatabase ---------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output) {
+ ++call_count_;
+ return wrapped_db_->FindFileByName(filename, output);
+ }
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output) {
+ ++call_count_;
+ return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
+ }
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ ++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() {}
+
+ DescriptorDatabase* wrapped_db_;
+
+ // implements DescriptorDatabase ---------------------------------
+ bool FindFileByName(const string& filename,
+ FileDescriptorProto* output) {
+ return wrapped_db_->FindFileByName(filename, output);
+ }
+ bool FindFileContainingSymbol(const string& symbol_name,
+ FileDescriptorProto* output) {
+ return FindFileByName("foo.proto", output);
+ }
+ bool FindFileContainingExtension(const string& containing_type,
+ int field_number,
+ FileDescriptorProto* output) {
+ return FindFileByName("foo.proto", output);
+ }
+ };
+};
+
+TEST_F(DatabaseBackedPoolTest, FindFileByName) {
+ DescriptorPool pool(&database_);
+
+ const FileDescriptor* foo = pool.FindFileByName("foo.proto");
+ ASSERT_TRUE(foo != NULL);
+ 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") == NULL);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
+ DescriptorPool pool(&database_);
+
+ const FileDescriptor* foo = pool.FindFileByName("foo.proto");
+ ASSERT_TRUE(foo != NULL);
+ 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 != NULL);
+ 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 != NULL);
+ 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 != NULL);
+ 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 != NULL);
+ EXPECT_EQ("foo.proto", file->name());
+ EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
+
+ EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == NULL);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
+ DescriptorPool pool(&database_);
+
+ const Descriptor* type = pool.FindMessageTypeByName("Foo");
+ ASSERT_TRUE(type != NULL);
+ EXPECT_EQ("Foo", type->name());
+ EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
+
+ EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == NULL);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
+ DescriptorPool pool(&database_);
+
+ const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+ ASSERT_TRUE(foo != NULL);
+
+ const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
+ ASSERT_TRUE(extension != NULL);
+ EXPECT_EQ("foo_ext", extension->name());
+ EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
+
+ EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == NULL);
+}
+
+TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
+ ErrorDescriptorDatabase error_database;
+ DescriptorPool pool(&error_database);
+
+ vector<string> errors;
+
+ {
+ ScopedMemoryLog log;
+ EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
+ 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") == NULL);
+ EXPECT_EQ(
+ "error.proto: error.proto: OTHER: File recursively imports itself: "
+ "error.proto -> error2.proto -> error.proto\n"
+ "error2.proto: error2.proto: OTHER: Import \"error.proto\" was not "
+ "found or had errors.\n"
+ "error.proto: error.proto: OTHER: Import \"error2.proto\" was not "
+ "found or had errors.\n",
+ error_collector.text_);
+}
+
+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 != NULL);
+
+ 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());
+}
+
+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 != NULL);
+ const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+ ASSERT_TRUE(foo != NULL);
+ const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
+ ASSERT_TRUE(test_enum != NULL);
+ const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
+ ASSERT_TRUE(test_service != NULL);
+
+ EXPECT_NE(0, call_counter.call_count_);
+ call_counter.Clear();
+
+ EXPECT_TRUE(foo->FindFieldByName("no_such_field") == NULL);
+ EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == NULL);
+ EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == NULL);
+ EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == NULL);
+ EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == NULL);
+
+ EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == NULL);
+ EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == NULL);
+ EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL);
+ EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL);
+ 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 != NULL);
+
+ // Try inducing false positives.
+ EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == NULL);
+ EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == NULL);
+
+ // No errors should have been reported. (If foo.proto was incorrectly
+ // loaded multiple times, errors would have been reported.)
+ EXPECT_EQ("", error_collector.text_);
+}
+
+TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
+ ErrorDescriptorDatabase error_database;
+ MockErrorCollector error_collector;
+ DescriptorPool pool(&error_database, &error_collector);
+
+ EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
+ error_collector.text_.clear();
+ EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
+ EXPECT_EQ("", error_collector.text_);
+}
+
+} // anonymous namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
new file mode 100644
index 00000000..43e2451e
--- /dev/null
+++ b/src/google/protobuf/dynamic_message.cc
@@ -0,0 +1,475 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 GeneratedMessageReflection to implement our reflection
+// interface. All the other operations we need to implement (e.g.
+// parsing, copying, etc.) are already implemented in terms of
+// Message::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[]". This is because "operator new()" means "Give me some
+// space which I can use as I please." while "new uint8[]" 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 <algorithm>
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format.h>
+
+namespace google {
+namespace protobuf {
+
+using internal::WireFormat;
+using internal::ExtensionSet;
+using internal::GeneratedMessageReflection;
+using internal::GenericRepeatedField;
+
+
+// ===================================================================
+// Some helper tables and functions...
+
+namespace {
+
+// 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 >);
+ case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
+ case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
+ case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
+ 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: return sizeof(RepeatedPtrField<Message>);
+
+ case FD::CPPTYPE_STRING:
+ return sizeof(RepeatedPtrField<string>);
+ break;
+ }
+ } else {
+ switch (field->cpp_type()) {
+ case FD::CPPTYPE_INT32 : return sizeof(int32 );
+ case FD::CPPTYPE_INT64 : return sizeof(int64 );
+ case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
+ case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
+ 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:
+ return sizeof(string*);
+ break;
+ }
+ }
+
+ GOOGLE_LOG(DFATAL) << "Can't get here.";
+ return 0;
+}
+
+struct DescendingFieldSizeOrder {
+ inline bool operator()(const FieldDescriptor* a,
+ const FieldDescriptor* b) {
+ // All repeated fields come first.
+ if (a->is_repeated()) {
+ if (b->is_repeated()) {
+ // Repeated fields and are not ordered with respect to each other.
+ return false;
+ } else {
+ return true;
+ }
+ } else if (b->is_repeated()) {
+ return false;
+ } else {
+ // Remaining fields in descending order by size.
+ return FieldSpaceUsed(a) > FieldSpaceUsed(b);
+ }
+ }
+};
+
+inline int DivideRoundingUp(int i, int j) {
+ return (i + (j - 1)) / j;
+}
+
+#define bitsizeof(T) (sizeof(T) * 8)
+
+} // namespace
+
+// ===================================================================
+
+class DynamicMessage : public Message {
+ public:
+ DynamicMessage(const Descriptor* descriptor,
+ uint8* base, const uint8* prototype_base,
+ int size, const int offsets[],
+ const DescriptorPool* pool, DynamicMessageFactory* factory);
+ ~DynamicMessage();
+
+ // Called on the prototype after construction to initialize message fields.
+ void CrossLinkPrototypes(DynamicMessageFactory* factory);
+
+ // implements Message ----------------------------------------------
+
+ Message* New() const;
+
+ int GetCachedSize() const;
+ void SetCachedSize(int size) const;
+
+ const Descriptor* GetDescriptor() const;
+ const Reflection* GetReflection() const;
+ Reflection* GetReflection();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
+
+ inline bool is_prototype() { return base_ == prototype_base_; }
+
+ const Descriptor* descriptor_;
+ const DescriptorPool* descriptor_pool_;
+ DynamicMessageFactory* factory_;
+ scoped_ptr<ExtensionSet> extensions_;
+ GeneratedMessageReflection reflection_;
+ uint8* base_;
+ const uint8* prototype_base_;
+ const int* offsets_;
+ int size_;
+
+ // TODO(kenton): Make this an atomic<int> when C++ supports it.
+ mutable int cached_byte_size_;
+};
+
+DynamicMessage::DynamicMessage(const Descriptor* descriptor,
+ uint8* base, const uint8* prototype_base,
+ int size, const int offsets[],
+ const DescriptorPool* pool,
+ DynamicMessageFactory* factory)
+ : descriptor_(descriptor),
+ descriptor_pool_((pool == NULL) ? descriptor->file()->pool() : pool),
+ factory_(factory),
+ extensions_(descriptor->extension_range_count() > 0 ?
+ new ExtensionSet(descriptor, descriptor_pool_, factory_) :
+ NULL),
+ reflection_(descriptor, base, prototype_base, offsets,
+ // has_bits
+ reinterpret_cast<uint32*>(base + size) -
+ DivideRoundingUp(descriptor->field_count(), bitsizeof(uint32)),
+ extensions_.get()),
+ base_(base),
+ prototype_base_(prototype_base),
+ offsets_(offsets),
+ size_(size),
+ cached_byte_size_(0) {
+ // 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.)
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ void* field_ptr = base + offsets[i];
+ 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>(); \
+ } \
+ break;
+
+ HANDLE_TYPE(INT32 , int32 );
+ HANDLE_TYPE(INT64 , int64 );
+ HANDLE_TYPE(UINT32, uint32);
+ HANDLE_TYPE(UINT64, uint64);
+ HANDLE_TYPE(DOUBLE, double);
+ HANDLE_TYPE(FLOAT , float );
+ HANDLE_TYPE(BOOL , bool );
+#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>();
+ }
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (!field->is_repeated()) {
+ if (is_prototype()) {
+ new(field_ptr) const string*(&field->default_value_string());
+ } else {
+ string* default_value =
+ *reinterpret_cast<string* const*>(
+ prototype_base + offsets[i]);
+ new(field_ptr) string*(default_value);
+ }
+ } else {
+ new(field_ptr) RepeatedPtrField<string>();
+ }
+ break;
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ // If this object is the prototype, its CPPTYPE_MESSAGE fields
+ // must be initialized later, in CrossLinkPrototypes(), so we don't
+ // initialize them here.
+ if (!is_prototype()) {
+ if (!field->is_repeated()) {
+ new(field_ptr) Message*(NULL);
+ } else {
+ const RepeatedPtrField<Message>* prototype_field =
+ reinterpret_cast<const RepeatedPtrField<Message>*>(
+ prototype_base + offsets[i]);
+ new(field_ptr) RepeatedPtrField<Message>(
+ prototype_field->prototype());
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+DynamicMessage::~DynamicMessage() {
+ // We need to manually run the destructors for repeated fields and strings,
+ // just as we ran their constructors in the the DynamicMessage constructor.
+ // 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.
+ const Descriptor* descriptor = GetDescriptor();
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ void* field_ptr = base_ + offsets_[i];
+
+ if (field->is_repeated()) {
+ GenericRepeatedField* field =
+ reinterpret_cast<GenericRepeatedField*>(field_ptr);
+ field->~GenericRepeatedField();
+
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ string* ptr = *reinterpret_cast<string**>(field_ptr);
+ if (ptr != &field->default_value_string()) {
+ delete ptr;
+ }
+ } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
+ !is_prototype()) {
+ Message* message = *reinterpret_cast<Message**>(field_ptr);
+ if (message != NULL) {
+ delete message;
+ }
+ }
+ }
+
+ // OK, now we can delete our base pointer.
+ operator delete(base_);
+
+ // When the prototype is deleted, we also want to free the offsets table.
+ // (The prototype is only deleted when the factory that created it is
+ // deleted.)
+ if (is_prototype()) {
+ delete [] offsets_;
+ }
+}
+
+void DynamicMessage::CrossLinkPrototypes(DynamicMessageFactory* factory) {
+ // This should only be called on the prototype message.
+ GOOGLE_CHECK(is_prototype());
+
+ // Cross-link default messages.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ void* field_ptr = base_ + offsets_[i];
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // For fields with message types, we need to cross-link with the
+ // prototype for the field's type.
+ const Message* field_prototype =
+ factory->GetPrototype(field->message_type());
+
+ if (field->is_repeated()) {
+ // For repeated fields, we actually construct the RepeatedPtrField
+ // here, but only for fields with message types. All other repeated
+ // fields are constructed in DynamicMessage's constructor.
+ new(field_ptr) RepeatedPtrField<Message>(field_prototype);
+ } else {
+ // For singular fields, the field is just a pointer which should
+ // point to the prototype. (OK to const_cast here because the
+ // prototype itself will only be available const to the outside
+ // world.)
+ new(field_ptr) Message*(const_cast<Message*>(field_prototype));
+ }
+ }
+ }
+}
+
+Message* DynamicMessage::New() const {
+ uint8* new_base = reinterpret_cast<uint8*>(operator new(size_));
+ memset(new_base, 0, size_);
+
+ return new DynamicMessage(GetDescriptor(), new_base, prototype_base_,
+ size_, offsets_, descriptor_pool_, factory_);
+}
+
+int DynamicMessage::GetCachedSize() const {
+ return cached_byte_size_;
+}
+
+void DynamicMessage::SetCachedSize(int size) const {
+ // This is theoretically not thread-compatible, but in practice it works
+ // because if multiple threads write this simultaneously, they will be
+ // writing the exact same value.
+ cached_byte_size_ = size;
+}
+
+const Descriptor* DynamicMessage::GetDescriptor() const {
+ return descriptor_;
+}
+
+const Message::Reflection* DynamicMessage::GetReflection() const {
+ return &reflection_;
+}
+
+Message::Reflection* DynamicMessage::GetReflection() {
+ return &reflection_;
+}
+
+// ===================================================================
+
+struct DynamicMessageFactory::PrototypeMap {
+ typedef hash_map<const Descriptor*, const Message*> Map;
+ Map map_;
+};
+
+DynamicMessageFactory::DynamicMessageFactory()
+ : pool_(NULL), prototypes_(new PrototypeMap) {
+}
+
+DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
+ : pool_(pool), prototypes_(new PrototypeMap) {
+}
+
+DynamicMessageFactory::~DynamicMessageFactory() {
+ for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
+ iter != prototypes_->map_.end(); ++iter) {
+ delete iter->second;
+ }
+}
+
+
+const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
+ const Message** target = &prototypes_->map_[type];
+ if (*target != NULL) {
+ // Already exists.
+ return *target;
+ }
+
+ // We need to construct all the structures passed to
+ // GeneratedMessageReflection'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.
+
+ // Compute size and offsets.
+ int* offsets = new int[type->field_count()];
+
+ // Sort the fields of this message in descending order by size. We
+ // assume that if we then pack the fields tightly in this order, all fields
+ // will end up properly-aligned, since all field sizes are powers of two or
+ // are multiples of the system word size.
+ scoped_array<const FieldDescriptor*> ordered_fields(
+ new const FieldDescriptor*[type->field_count()]);
+ for (int i = 0; i < type->field_count(); i++) {
+ ordered_fields[i] = type->field(i);
+ }
+ stable_sort(&ordered_fields[0], &ordered_fields[type->field_count()],
+ DescendingFieldSizeOrder());
+
+ // Decide all field offsets by packing in order.
+ int current_offset = 0;
+
+ for (int i = 0; i < type->field_count(); i++) {
+ offsets[ordered_fields[i]->index()] = current_offset;
+ current_offset += FieldSpaceUsed(ordered_fields[i]);
+ }
+
+ // Allocate space for all fields plus has_bits. We'll stick has_bits on
+ // the end.
+ int size = current_offset +
+ DivideRoundingUp(type->field_count(), bitsizeof(uint32)) * sizeof(uint32);
+
+ // Round size up to the nearest 64-bit boundary just to make sure no
+ // clever allocators think that alignment is not necessary. This also
+ // insures that has_bits is properly-aligned, since we'll always align
+ // has_bits with the end of the structure.
+ size = DivideRoundingUp(size, sizeof(uint64)) * sizeof(uint64);
+ uint8* base = reinterpret_cast<uint8*>(operator new(size));
+ memset(base, 0, size);
+
+ // Construct message.
+ DynamicMessage* result =
+ new DynamicMessage(type, base, base, size, offsets, pool_, this);
+ *target = result;
+ result->CrossLinkPrototypes(this);
+
+ return result;
+}
+
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
new file mode 100644
index 00000000..e5a9f908
--- /dev/null
+++ b/src/google/protobuf/dynamic_message.h
@@ -0,0 +1,105 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/message.h>
+#include <google/protobuf/stubs/common.h>
+
+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 LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
+ public:
+ // Construct a DynamicMessageFactory that will search for extensions in
+ // the DescriptorPool in which the exendee is defined.
+ DynamicMessageFactory();
+
+ // Construct a DynamicMessageFactory that will search for extensions in
+ // the given DescriptorPool.
+ DynamicMessageFactory(const DescriptorPool* pool);
+ ~DynamicMessageFactory();
+
+ // 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 destoyed before the DynamicMessageFactory
+ // is destroyed.
+ //
+ // The given descriptor must outlive the returned message, and hence must
+ // outlive the DynamicMessageFactory.
+ //
+ // Note that while GetPrototype() is idempotent, it is not const. This
+ // implies that it is not thread-safe to call GetPrototype() on the same
+ // DynamicMessageFactory in two different threads simultaneously. However,
+ // the returned objects are just as thread-safe as any other Message.
+ const Message* GetPrototype(const Descriptor* type);
+
+ private:
+ const DescriptorPool* pool_;
+
+ // This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
+ // this header due to hacks needed for hash_map portability in the open source
+ // release. Namely, stubs/hash.h, which defines hash_map portably, is not a
+ // public header (for good reason), but dynamic_message.h is, and public
+ // headers may only #include other public headers.
+ struct PrototypeMap;
+ scoped_ptr<PrototypeMap> prototypes_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..5afac1fc
--- /dev/null
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -0,0 +1,117 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/stubs/common.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+class DynamicMessageTest : public testing::Test {
+ protected:
+ DescriptorPool pool_;
+ DynamicMessageFactory factory_;
+ const Descriptor* descriptor_;
+ const Message* prototype_;
+ const Descriptor* extensions_descriptor_;
+ const Message* extensions_prototype_;
+
+ DynamicMessageTest(): factory_(&pool_) {}
+
+ virtual void SetUp() {
+ // 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;
+
+ unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
+ unittest_import::ImportMessage::descriptor()->file()->CopyTo(
+ &unittest_import_file);
+
+ ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
+ ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
+
+ descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
+ ASSERT_TRUE(descriptor_ != NULL);
+ prototype_ = factory_.GetPrototype(descriptor_);
+
+ extensions_descriptor_ =
+ pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions");
+ ASSERT_TRUE(extensions_descriptor_ != NULL);
+ extensions_prototype_ = factory_.GetPrototype(extensions_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_->GetReflection());
+}
+
+TEST_F(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).
+ scoped_ptr<Message> message(prototype_->New());
+ TestUtil::ReflectionTester reflection_tester(descriptor_);
+
+ reflection_tester.SetAllFieldsViaReflection(message->GetReflection());
+ reflection_tester.ExpectAllFieldsSetViaReflection(*message->GetReflection());
+}
+
+TEST_F(DynamicMessageTest, Extensions) {
+ // Check that extensions work.
+ scoped_ptr<Message> message(extensions_prototype_->New());
+ TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
+
+ reflection_tester.SetAllFieldsViaReflection(message->GetReflection());
+ reflection_tester.ExpectAllFieldsSetViaReflection(*message->GetReflection());
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
new file mode 100644
index 00000000..154f06f8
--- /dev/null
+++ b/src/google/protobuf/extension_set.cc
@@ -0,0 +1,735 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// -------------------------------------------------------------------
+// Lookup functions
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionByName(const string& name) const {
+ const FieldDescriptor* result = descriptor_pool_->FindExtensionByName(name);
+ if (result != NULL && result->containing_type() == extendee_) {
+ return result;
+ }
+
+ if (extendee_->options().message_set_wire_format()) {
+ // MessageSet extensions may be identified by type name.
+ const Descriptor* type = descriptor_pool_->FindMessageTypeByName(name);
+ if (type != NULL) {
+ // Look for a matching extension in the foreign type's scope.
+ 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 NULL;
+}
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionByNumber(int number) const {
+ return descriptor_pool_->FindExtensionByNumber(extendee_, number);
+}
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionOrDie(int number) const {
+ const FieldDescriptor* descriptor = FindKnownExtensionByNumber(number);
+ if (descriptor == NULL) {
+ // This extension doesn't exist, so we have to crash. However, let's
+ // try to provide an informative error message.
+ if (descriptor_pool_ == DescriptorPool::generated_pool() &&
+ message_factory_ == MessageFactory::generated_factory()) {
+ // This is probably the ExtensionSet for a generated class.
+ GOOGLE_LOG(FATAL) << ": No extension is registered for \""
+ << extendee_->full_name() << "\" with number "
+ << number << ". Perhaps you were trying to access it via "
+ "the Reflection interface, but you provided a "
+ "FieldDescriptor which did not come from a linked-in "
+ "message type? This is not permitted; linkin-in message "
+ "types cannot use non-linked-in extensions. Try "
+ "converting to a DynamicMessage first.";
+ } else {
+ // This is probably a DynamicMessage.
+ GOOGLE_LOG(FATAL) << ": No extension is registered for \""
+ << extendee_->full_name() << "\" with number "
+ << number << ". If you were using a DynamicMessage, "
+ "remember that you are only allowed to access extensions "
+ "which are defined in the DescriptorPool which you passed "
+ "to DynamicMessageFactory's constructor.";
+ }
+ }
+ return descriptor;
+}
+
+const Message*
+ExtensionSet::GetPrototype(const Descriptor* message_type) const {
+ return message_factory_->GetPrototype(message_type);
+}
+
+// ===================================================================
+// Constructors and basic methods.
+
+ExtensionSet::ExtensionSet(const Descriptor* extendee,
+ const DescriptorPool* pool,
+ MessageFactory* factory)
+ : extendee_(extendee),
+ descriptor_pool_(pool),
+ message_factory_(factory) {
+}
+
+ExtensionSet::~ExtensionSet() {
+ for (map<int, Extension>::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.Free();
+ }
+}
+
+void ExtensionSet::AppendToList(vector<const FieldDescriptor*>* output) const {
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ bool has = false;
+ if (iter->second.descriptor->is_repeated()) {
+ has = iter->second.GetSize() > 0;
+ } else {
+ has = !iter->second.is_cleared;
+ }
+
+ if (has) {
+ output->push_back(iter->second.descriptor);
+ }
+ }
+}
+
+bool ExtensionSet::Has(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return false;
+ GOOGLE_DCHECK(!iter->second.descriptor->is_repeated());
+ return !iter->second.is_cleared;
+}
+
+int ExtensionSet::ExtensionSize(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return false;
+ return iter->second.GetSize();
+}
+
+void ExtensionSet::ClearExtension(int number) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return;
+ iter->second.Clear();
+}
+
+// ===================================================================
+// Field accessors
+
+#define GOOGLE_DCHECK_TYPE(DESCRIPTOR, LABEL, CPPTYPE) \
+ GOOGLE_DCHECK_EQ(DESCRIPTOR->label(), FieldDescriptor::LABEL_##LABEL); \
+ GOOGLE_DCHECK_EQ(DESCRIPTOR->cpp_type(), FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+// -------------------------------------------------------------------
+// Primitives
+
+#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \
+ \
+LOWERCASE ExtensionSet::Get##CAMELCASE(int number) const { \
+ map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ if (iter == extensions_.end()) { \
+ /* Not present. Return the default value. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \
+ return descriptor->default_value_##LOWERCASE(); \
+ } else { \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, UPPERCASE); \
+ return iter->second.LOWERCASE##_value; \
+ } \
+} \
+ \
+void ExtensionSet::Set##CAMELCASE(int number, LOWERCASE value) { \
+ Extension* extension = &extensions_[number]; \
+ if (extension->descriptor == NULL) { \
+ /* Not previoulsy present. Initialize it. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \
+ extension->descriptor = descriptor; \
+ extension->LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \
+ } else { \
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, UPPERCASE); \
+ extension->is_cleared = false; \
+ } \
+ extension->LOWERCASE##_value = value; \
+} \
+ \
+LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \
+ map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \
+ return iter->second.repeated_##LOWERCASE##_value->Get(index); \
+} \
+ \
+void ExtensionSet::SetRepeated##CAMELCASE( \
+ int number, int index, LOWERCASE value) { \
+ map<int, Extension>::iterator iter = extensions_.find(number); \
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \
+ iter->second.repeated_##LOWERCASE##_value->Set(index, value); \
+} \
+ \
+void ExtensionSet::Add##CAMELCASE(int number, LOWERCASE value) { \
+ Extension* extension = &extensions_[number]; \
+ if (extension->descriptor == NULL) { \
+ /* Not previoulsy present. Initialize it. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, UPPERCASE); \
+ extension->repeated_##LOWERCASE##_value = new RepeatedField<LOWERCASE>(); \
+ extension->descriptor = descriptor; \
+ } else { \
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, UPPERCASE); \
+ } \
+ extension->repeated_##LOWERCASE##_value->Add(value); \
+}
+
+PRIMITIVE_ACCESSORS( INT32, int32, Int32)
+PRIMITIVE_ACCESSORS( INT64, int64, Int64)
+PRIMITIVE_ACCESSORS(UINT32, uint32, UInt32)
+PRIMITIVE_ACCESSORS(UINT64, uint64, UInt64)
+PRIMITIVE_ACCESSORS( FLOAT, float, Float)
+PRIMITIVE_ACCESSORS(DOUBLE, double, Double)
+PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
+
+#undef PRIMITIVE_ACCESSORS
+
+// -------------------------------------------------------------------
+// Enums
+
+int ExtensionSet::GetEnum(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM);
+ return descriptor->default_value_enum()->number();
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, ENUM);
+ return iter->second.enum_value;
+ }
+}
+
+void ExtensionSet::SetEnum(int number, int value) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM);
+ extension->descriptor = descriptor;
+ extension->enum_value = descriptor->default_value_enum()->number();
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, ENUM);
+ extension->is_cleared = false;
+ }
+ GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL);
+ extension->enum_value = value;
+}
+
+int ExtensionSet::GetRepeatedEnum(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM);
+ return iter->second.repeated_enum_value->Get(index);
+}
+
+void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM);
+ GOOGLE_DCHECK(iter->second.descriptor->enum_type()
+ ->FindValueByNumber(value) != NULL);
+ iter->second.repeated_enum_value->Set(index, value);
+}
+
+void ExtensionSet::AddEnum(int number, int value) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, ENUM);
+ extension->repeated_enum_value = new RepeatedField<int>();
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, ENUM);
+ }
+ GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL);
+ extension->repeated_enum_value->Add(value);
+}
+
+// -------------------------------------------------------------------
+// Strings
+
+const string& ExtensionSet::GetString(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING);
+ return descriptor->default_value_string();
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, STRING);
+ return *iter->second.string_value;
+ }
+}
+
+string* ExtensionSet::MutableString(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING);
+ extension->descriptor = descriptor;
+ extension->string_value = new string;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, STRING);
+ extension->is_cleared = false;
+ }
+ return extension->string_value;
+}
+
+const string& ExtensionSet::GetRepeatedString(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING);
+ return iter->second.repeated_string_value->Get(index);
+}
+
+string* ExtensionSet::MutableRepeatedString(int number, int index) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING);
+ return iter->second.repeated_string_value->Mutable(index);
+}
+
+string* ExtensionSet::AddString(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, STRING);
+ extension->repeated_string_value = new RepeatedPtrField<string>();
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, STRING);
+ }
+ return extension->repeated_string_value->Add();
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+const Message& ExtensionSet::GetMessage(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE);
+ return *GetPrototype(descriptor->message_type());
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, MESSAGE);
+ return *iter->second.message_value;
+ }
+}
+
+Message* ExtensionSet::MutableMessage(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE);
+ extension->descriptor = descriptor;
+ extension->message_value = GetPrototype(descriptor->message_type())->New();
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ }
+ return extension->message_value;
+}
+
+const Message& ExtensionSet::GetRepeatedMessage(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE);
+ return iter->second.repeated_message_value->Get(index);
+}
+
+Message* ExtensionSet::MutableRepeatedMessage(int number, int index) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE);
+ return iter->second.repeated_message_value->Mutable(index);
+}
+
+Message* ExtensionSet::AddMessage(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, MESSAGE);
+ extension->repeated_message_value =
+ new RepeatedPtrField<Message>(GetPrototype(descriptor->message_type()));
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, MESSAGE);
+ }
+ return extension->repeated_message_value->Add();
+}
+
+#undef GOOGLE_DCHECK_TYPE
+
+// ===================================================================
+
+void ExtensionSet::Clear() {
+ for (map<int, Extension>::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.Clear();
+ }
+}
+
+namespace {
+
+// A helper function for merging RepeatedFields...
+// TODO(kenton): Implement this as a method of RepeatedField? Make generated
+// MergeFrom methods use it?
+
+template <typename Type>
+void MergeRepeatedFields(const RepeatedField<Type>& source,
+ RepeatedField<Type>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add(source.Get(i));
+ }
+}
+
+void MergeRepeatedFields(const RepeatedPtrField<string>& source,
+ RepeatedPtrField<string>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add()->assign(source.Get(i));
+ }
+}
+
+void MergeRepeatedFields(const RepeatedPtrField<Message>& source,
+ RepeatedPtrField<Message>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add()->MergeFrom(source.Get(i));
+ }
+}
+
+} // namespace
+
+void ExtensionSet::MergeFrom(const ExtensionSet& other) {
+ GOOGLE_DCHECK_EQ(extendee_, other.extendee_);
+
+ for (map<int, Extension>::const_iterator iter = other.extensions_.begin();
+ iter != other.extensions_.end(); ++iter) {
+ const FieldDescriptor* field = iter->second.descriptor;
+ if (field->is_repeated()) {
+ const Extension& other_extension = iter->second;
+ Extension* extension = &extensions_[iter->first];
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ if (extension->descriptor == NULL) { \
+ extension->descriptor = field; \
+ extension->repeated_##LOWERCASE##_value = \
+ new REPEATED_TYPE; \
+ } \
+ MergeRepeatedFields( \
+ *other_extension.repeated_##LOWERCASE##_value, \
+ extension->repeated_##LOWERCASE##_value); \
+ break;
+
+ HANDLE_TYPE( INT32, int32, RepeatedField < int32>);
+ HANDLE_TYPE( INT64, int64, RepeatedField < int64>);
+ HANDLE_TYPE( UINT32, uint32, RepeatedField < uint32>);
+ HANDLE_TYPE( UINT64, uint64, RepeatedField < uint64>);
+ HANDLE_TYPE( FLOAT, float, RepeatedField < float>);
+ HANDLE_TYPE( DOUBLE, double, RepeatedField < double>);
+ HANDLE_TYPE( BOOL, bool, RepeatedField < bool>);
+ HANDLE_TYPE( ENUM, enum, RepeatedField < int>);
+ HANDLE_TYPE( STRING, string, RepeatedPtrField< string>);
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ if (extension->descriptor == NULL) {
+ extension->descriptor = field;
+ extension->repeated_message_value = new RepeatedPtrField<Message>(
+ other_extension.repeated_message_value->prototype());
+ }
+ MergeRepeatedFields(
+ *other_extension.repeated_message_value,
+ extension->repeated_message_value);
+ break;
+ }
+ } else {
+ if (!iter->second.is_cleared) {
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ Set##CAMELCASE(iter->first, iter->second.LOWERCASE##_value); \
+ break;
+
+ HANDLE_TYPE( INT32, int32, Int32);
+ HANDLE_TYPE( INT64, int64, Int64);
+ HANDLE_TYPE(UINT32, uint32, UInt32);
+ HANDLE_TYPE(UINT64, uint64, UInt64);
+ HANDLE_TYPE( FLOAT, float, Float);
+ HANDLE_TYPE(DOUBLE, double, Double);
+ HANDLE_TYPE( BOOL, bool, Bool);
+ HANDLE_TYPE( ENUM, enum, Enum);
+#undef HANDLE_TYPE
+ case FieldDescriptor::CPPTYPE_STRING:
+ SetString(iter->first, *iter->second.string_value);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ MutableMessage(iter->first)->MergeFrom(*iter->second.message_value);
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool ExtensionSet::IsInitialized() const {
+ // Extensions are never requried. However, we need to check that all
+ // embedded messages are initialized.
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ const Extension& extension = iter->second;
+ if (extension.descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (extension.descriptor->is_repeated()) {
+ for (int i = 0; i < extension.repeated_message_value->size(); i++) {
+ if (!extension.repeated_message_value->Get(i).IsInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!extension.is_cleared) {
+ if (!extension.message_value->IsInitialized()) return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+ Message::Reflection* reflection) {
+ const FieldDescriptor* field =
+ FindKnownExtensionByNumber(WireFormat::GetTagFieldNumber(tag));
+
+ return WireFormat::ParseAndMergeField(tag, field, reflection, input);
+}
+
+bool ExtensionSet::SerializeWithCachedSizes(
+ int start_field_number, int end_field_number,
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const {
+ map<int, Extension>::const_iterator iter;
+ for (iter = extensions_.lower_bound(start_field_number);
+ iter != extensions_.end() && iter->first < end_field_number;
+ ++iter) {
+ if (!iter->second.SerializeFieldWithCachedSizes(reflection, output)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int ExtensionSet::ByteSize(const Message::Reflection* reflection) const {
+ int total_size = 0;
+
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ total_size += iter->second.ByteSize(reflection);
+ }
+
+ return total_size;
+}
+
+// ===================================================================
+// Methods of ExtensionSet::Extension
+
+void ExtensionSet::Extension::Clear() {
+ if (descriptor->is_repeated()) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ repeated_##LOWERCASE##_value->Clear(); \
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+ } else {
+ if (!is_cleared) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \
+ 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);
+#undef HANDLE_TYPE
+ case FieldDescriptor::CPPTYPE_ENUM:
+ enum_value = descriptor->default_value_enum()->number();
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (descriptor->has_default_value()) {
+ string_value->assign(descriptor->default_value_string());
+ } else {
+ string_value->clear();
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ message_value->Clear();
+ break;
+ }
+
+ is_cleared = true;
+ }
+ }
+}
+
+bool ExtensionSet::Extension::SerializeFieldWithCachedSizes(
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const {
+ if (descriptor->is_repeated() || !is_cleared) {
+ return WireFormat::SerializeFieldWithCachedSizes(
+ descriptor, reflection, output);
+ } else {
+ return true;
+ }
+}
+
+int64 ExtensionSet::Extension::ByteSize(
+ const Message::Reflection* reflection) const {
+ if (descriptor->is_repeated() || !is_cleared) {
+ return WireFormat::FieldByteSize(descriptor, reflection);
+ } else {
+ // Cleared, non-repeated field.
+ return 0;
+ }
+}
+
+int ExtensionSet::Extension::GetSize() const {
+ GOOGLE_DCHECK(descriptor->is_repeated());
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ return repeated_##LOWERCASE##_value->size()
+
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return 0;
+}
+
+void ExtensionSet::Extension::Free() {
+ if (descriptor->is_repeated()) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ delete repeated_##LOWERCASE##_value; \
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+ } else {
+ switch (descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_STRING:
+ delete string_value;
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ delete message_value;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
new file mode 100644
index 00000000..902ec736
--- /dev/null
+++ b/src/google/protobuf/extension_set.h
@@ -0,0 +1,555 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <vector>
+#include <stack>
+#include <map>
+#include <utility>
+#include <string>
+
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+ class Descriptor; // descriptor.h
+ class FieldDescriptor; // descriptor.h
+ class DescriptorPool; // descriptor.h
+ class Message; // message.h
+ class MessageFactory; // message.h
+ namespace io {
+ class CodedInputStream; // coded_stream.h
+ class CodedOutputStream; // coded_stream.h
+ }
+ template <typename Element> class RepeatedField; // repeated_field.h
+ template <typename Element> class RepeatedPtrField; // repeated_field.h
+}
+
+namespace protobuf {
+namespace internal {
+
+// 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 LIBPROTOBUF_EXPORT ExtensionSet {
+ public:
+ // Construct an ExtensionSet.
+ // extendee: Descriptor for the type being extended.
+ // pool: DescriptorPool to search for extension definitions.
+ // factory: MessageFactory used to construct implementations of messages
+ // for extensions with message type. This factory must be able
+ // to construct any message type found in "pool".
+ // All three objects remain property of the caller and must outlive the
+ // ExtensionSet.
+ ExtensionSet(const Descriptor* extendee,
+ const DescriptorPool* pool,
+ MessageFactory* factory);
+
+ ~ExtensionSet();
+
+ // Search for a known (compiled-in) extension of this type by name or number.
+ // Returns NULL if no extension is known.
+ const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
+ const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
+
+ // Add all fields which are currently present to the given vector. This
+ // is useful to implement Message::Reflection::ListFields().
+ void AppendToList(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. Otheriwse,
+ // 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 Message::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.
+ void ClearExtension(int number);
+
+ // singular fields -------------------------------------------------
+
+ int32 GetInt32 (int number) const;
+ int64 GetInt64 (int number) const;
+ uint32 GetUInt32(int number) const;
+ uint64 GetUInt64(int number) const;
+ float GetFloat (int number) const;
+ double GetDouble(int number) const;
+ bool GetBool (int number) const;
+ int GetEnum (int number) const;
+ const string & GetString (int number) const;
+ const Message& GetMessage(int number) const;
+
+ void SetInt32 (int number, int32 value);
+ void SetInt64 (int number, int64 value);
+ void SetUInt32(int number, uint32 value);
+ void SetUInt64(int number, uint64 value);
+ void SetFloat (int number, float value);
+ void SetDouble(int number, double value);
+ void SetBool (int number, bool value);
+ void SetEnum (int number, int value);
+ void SetString(int number, const string& value);
+ string * MutableString (int number);
+ Message* MutableMessage(int number);
+
+ // repeated fields -------------------------------------------------
+
+ int32 GetRepeatedInt32 (int number, int index) const;
+ int64 GetRepeatedInt64 (int number, int index) const;
+ uint32 GetRepeatedUInt32(int number, int index) const;
+ uint64 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 string & GetRepeatedString (int number, int index) const;
+ const Message& GetRepeatedMessage(int number, int index) const;
+
+ void SetRepeatedInt32 (int number, int index, int32 value);
+ void SetRepeatedInt64 (int number, int index, int64 value);
+ void SetRepeatedUInt32(int number, int index, uint32 value);
+ void SetRepeatedUInt64(int number, int index, uint64 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, const string& value);
+ string * MutableRepeatedString (int number, int index);
+ Message* MutableRepeatedMessage(int number, int index);
+
+ void AddInt32 (int number, int32 value);
+ void AddInt64 (int number, int64 value);
+ void AddUInt32(int number, uint32 value);
+ void AddUInt64(int number, uint64 value);
+ void AddFloat (int number, float value);
+ void AddDouble(int number, double value);
+ void AddBool (int number, bool value);
+ void AddEnum (int number, int value);
+ void AddString(int number, const string& value);
+ string * AddString (int number);
+ Message* AddMessage(int number);
+
+ // -----------------------------------------------------------------
+ // TODO(kenton): Hardcore memory management accessors
+
+ // =================================================================
+ // 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 ExtensionSet& other);
+ bool IsInitialized() const;
+
+ // These parsing and serialization functions all want a pointer to the
+ // reflection interface because they hand off the actual work to WireFormat,
+ // which works in terms of a reflection interface. Yes, this means there
+ // are some redundant virtual function calls that end up being made, but
+ // it probably doesn't matter much in practice, and the alternative would
+ // involve reproducing a lot of WireFormat's functionality.
+
+ // Parses a single extension from the input. The input should start out
+ // positioned immediately after the tag.
+ bool ParseField(uint32 tag, io::CodedInputStream* input,
+ Message::Reflection* reflection);
+
+ // 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.
+ bool SerializeWithCachedSizes(int start_field_number,
+ int end_field_number,
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const;
+
+ // Returns the total serialized size of all the extensions.
+ int ByteSize(const Message::Reflection* reflection) const;
+
+ private:
+ // Like FindKnownExtension(), but GOOGLE_CHECK-fail if not found.
+ const FieldDescriptor* FindKnownExtensionOrDie(int number) const;
+
+ // Get the prototype for the message.
+ const Message* GetPrototype(const Descriptor* message_type) const;
+
+ struct Extension {
+ union {
+ int32 int32_value;
+ int64 int64_value;
+ uint32 uint32_value;
+ uint64 uint64_value;
+ float float_value;
+ double double_value;
+ bool bool_value;
+ int enum_value;
+ string* string_value;
+ Message* message_value;
+
+ RepeatedField <int32 >* repeated_int32_value;
+ RepeatedField <int64 >* repeated_int64_value;
+ RepeatedField <uint32 >* repeated_uint32_value;
+ RepeatedField <uint64 >* repeated_uint64_value;
+ RepeatedField <float >* repeated_float_value;
+ RepeatedField <double >* repeated_double_value;
+ RepeatedField <bool >* repeated_bool_value;
+ RepeatedField <int >* repeated_enum_value;
+ RepeatedPtrField<string >* repeated_string_value;
+ RepeatedPtrField<Message>* repeated_message_value;
+ };
+
+ const FieldDescriptor* descriptor;
+
+ // 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;
+
+ Extension(): descriptor(NULL), is_cleared(false) {}
+
+ // Some helper methods for operations on a single Extension.
+ bool SerializeFieldWithCachedSizes(
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const;
+ int64 ByteSize(const Message::Reflection* reflection) const;
+ void Clear();
+ int GetSize() const;
+ void Free();
+ };
+
+ // The Extension struct is small enough to be passed by value, so we use it
+ // directly as the value type in the map rather than use pointers. We use
+ // a map rather than hash_map here because we expect most ExtensionSets will
+ // only contain a small number of extensions whereas hash_map is optimized
+ // for 100 elements or more. Also, we want AppendToList() to order fields
+ // by field number.
+ map<int, Extension> extensions_;
+ const Descriptor* extendee_;
+ const DescriptorPool* descriptor_pool_;
+ MessageFactory* message_factory_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
+};
+
+// These are just for convenience...
+inline void ExtensionSet::SetString(int number, const string& value) {
+ MutableString(number)->assign(value);
+}
+inline void ExtensionSet::SetRepeatedString(int number, int index,
+ const string& value) {
+ MutableRepeatedString(number, index)->assign(value);
+}
+inline void ExtensionSet::AddString(int number, const string& value) {
+ AddString(number)->assign(value);
+}
+
+// ===================================================================
+// Implementation details
+//
+// DO NOT DEPEND ON ANYTHING BELOW THIS POINT. This is for use from
+// generated code only.
+
+// -------------------------------------------------------------------
+// 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;
+//
+// 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);
+// };
+//
+// 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> 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;
+
+ static inline ConstType Get(int number, const ExtensionSet& set);
+ static inline void Set(int number, ConstType value, ExtensionSet* set);
+};
+
+template <typename Type>
+class RepeatedPrimitiveTypeTraits {
+ public:
+ typedef Type ConstType;
+
+ static inline Type Get(int number, const ExtensionSet& set, int index);
+ static inline void Set(int number, int index, Type value, ExtensionSet* set);
+ static inline void Add(int number, Type value, ExtensionSet* set);
+};
+
+#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \
+template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get( \
+ int number, const ExtensionSet& set) { \
+ return set.Get##METHOD(number); \
+} \
+template<> inline void PrimitiveTypeTraits<TYPE>::Set( \
+ int number, ConstType value, ExtensionSet* set) { \
+ set->Set##METHOD(number, value); \
+} \
+ \
+template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get( \
+ int number, const ExtensionSet& set, int index) { \
+ return set.GetRepeated##METHOD(number, index); \
+} \
+template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set( \
+ int number, int index, ConstType value, ExtensionSet* set) { \
+ set->SetRepeated##METHOD(number, index, value); \
+} \
+template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
+ int number, ConstType value, ExtensionSet* set) { \
+ set->Add##METHOD(number, value); \
+}
+
+PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, 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 LIBPROTOBUF_EXPORT StringTypeTraits {
+ public:
+ typedef const string& ConstType;
+ typedef string* MutableType;
+
+ static inline const string& Get(int number, const ExtensionSet& set) {
+ return set.GetString(number);
+ }
+ static inline void Set(int number, const string& value, ExtensionSet* set) {
+ set->SetString(number, value);
+ }
+ static inline string* Mutable(int number, ExtensionSet* set) {
+ return set->MutableString(number);
+ }
+};
+
+class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
+ public:
+ typedef const string& ConstType;
+ typedef string* MutableType;
+
+ static inline const string& Get(int number, const ExtensionSet& set,
+ int index) {
+ return set.GetRepeatedString(number, index);
+ }
+ static inline void Set(int number, int index,
+ const string& value, ExtensionSet* set) {
+ set->SetRepeatedString(number, index, value);
+ }
+ static inline string* Mutable(int number, int index, ExtensionSet* set) {
+ return set->MutableRepeatedString(number, index);
+ }
+ static inline void Add(int number, const string& value, ExtensionSet* set) {
+ set->AddString(number, value);
+ }
+ static inline string* Add(int number, ExtensionSet* set) {
+ return set->AddString(number);
+ }
+};
+
+// -------------------------------------------------------------------
+// EnumTypeTraits
+
+// ExtensionSet represents enums using integers internally, so we have to
+// static_cast around.
+template <typename Type>
+class EnumTypeTraits {
+ public:
+ typedef Type ConstType;
+
+ static inline ConstType Get(int number, const ExtensionSet& set) {
+ return static_cast<Type>(set.GetEnum(number));
+ }
+ static inline void Set(int number, ConstType value, ExtensionSet* set) {
+ set->SetEnum(number, value);
+ }
+};
+
+template <typename Type>
+class RepeatedEnumTypeTraits {
+ public:
+ typedef Type ConstType;
+
+ static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+ return static_cast<Type>(set.GetRepeatedEnum(number, index));
+ }
+ static inline void Set(int number, int index,
+ ConstType value, ExtensionSet* set) {
+ set->SetRepeatedEnum(number, index, value);
+ }
+ static inline void Add(int number, ConstType value, ExtensionSet* set) {
+ set->AddEnum(number, value);
+ }
+};
+
+// -------------------------------------------------------------------
+// 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;
+
+ static inline ConstType Get(int number, const ExtensionSet& set) {
+ return static_cast<const Type&>(set.GetMessage(number));
+ }
+ static inline MutableType Mutable(int number, ExtensionSet* set) {
+ return static_cast<Type*>(set->MutableMessage(number));
+ }
+};
+
+template <typename Type>
+class RepeatedMessageTypeTraits {
+ public:
+ typedef const Type& ConstType;
+ typedef Type* MutableType;
+
+ static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+ return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
+ }
+ static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
+ return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
+ }
+ static inline MutableType Add(int number, ExtensionSet* set) {
+ return static_cast<Type*>(set->AddMessage(number));
+ }
+};
+
+// -------------------------------------------------------------------
+// ExtensionIdentifier
+
+// This is the type of actual extension objects. E.g. if you have:
+// extends Foo with optional int32 bar = 1234;
+// then "bar" will be defined in C++ as:
+// ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>> 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 at extension
+// identifier would not necessarily cause the compiler to output any sort
+// of reference to any simple 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>
+class ExtensionIdentifier {
+ public:
+ typedef TypeTraitsType TypeTraits;
+ typedef ExtendeeType Extendee;
+
+ ExtensionIdentifier(int number): number_(number) {}
+ inline int number() const { return number_; }
+ private:
+ const int number_;
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
new file mode 100644
index 00000000..c10f8900
--- /dev/null
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -0,0 +1,195 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+// This test closely mirrors google/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);
+
+ // Unlike with the defaults test, we do NOT expect that requesting embedded
+ // messages will return a pointer to the default instance. Instead, they
+ // should return the objects that were created when mutable_blah() was
+ // called.
+ 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(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 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, CopyFrom) {
+ unittest::TestAllExtensions message1, message2;
+ string data;
+
+ TestUtil::SetAllExtensions(&message1);
+ message2.CopyFrom(message1);
+ TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, Serialization) {
+ // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
+ // compatibility of extensions.
+ unittest::TestAllExtensions source;
+ unittest::TestAllTypes destination;
+ string data;
+
+ TestUtil::SetAllExtensions(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectAllFieldsSet(destination);
+}
+
+TEST(ExtensionSetTest, Parsing) {
+ // Serialize as TestAllTypes and parse as TestAllExtensions.
+ unittest::TestAllTypes source;
+ unittest::TestAllExtensions destination;
+ string data;
+
+ TestUtil::SetAllFields(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectAllExtensionsSet(destination);
+}
+
+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));
+}
+
+} // namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
new file mode 100644
index 00000000..ec17572b
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -0,0 +1,665 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace { const string kEmptyString; }
+
+// ===================================================================
+// Helpers for reporting usage errors (e.g. trying to use GetInt32() on
+// a string field).
+
+namespace {
+
+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::Message::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::Message::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::Message::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();
+}
+
+#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
+
+// ===================================================================
+
+GeneratedMessageReflection::GeneratedMessageReflection(
+ const Descriptor* descriptor,
+ void* base, const void* default_base,
+ const int offsets[], uint32 has_bits[],
+ ExtensionSet* extensions)
+ : descriptor_ (descriptor),
+ base_ (base),
+ default_base_(default_base),
+ offsets_ (offsets),
+ has_bits_ (has_bits),
+ extensions_ (extensions) {
+}
+
+GeneratedMessageReflection::~GeneratedMessageReflection() {}
+
+const UnknownFieldSet& GeneratedMessageReflection::GetUnknownFields() const {
+ return unknown_fields_;
+}
+UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields() {
+ return &unknown_fields_;
+}
+
+// -------------------------------------------------------------------
+
+bool GeneratedMessageReflection::HasField(const FieldDescriptor* field) const {
+ USAGE_CHECK_MESSAGE_TYPE(HasField);
+ USAGE_CHECK_SINGULAR(HasField);
+
+ if (field->is_extension()) {
+ return extensions_->Has(field->number());
+ } else {
+ return HasBit(field);
+ }
+}
+
+int GeneratedMessageReflection::FieldSize(const FieldDescriptor* field) const {
+ USAGE_CHECK_MESSAGE_TYPE(HasField);
+ USAGE_CHECK_REPEATED(HasField);
+
+ if (field->is_extension()) {
+ return extensions_->ExtensionSize(field->number());
+ } else {
+ return GetRaw<GenericRepeatedField>(field).GenericSize();
+ }
+}
+
+void GeneratedMessageReflection::ClearField(const FieldDescriptor* field) {
+ USAGE_CHECK_MESSAGE_TYPE(ClearField);
+
+ if (field->is_extension()) {
+ extensions_->ClearExtension(field->number());
+ } else if (!field->is_repeated()) {
+ if (HasBit(field)) {
+ ClearBit(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>(field) = field->default_value_##TYPE(); \
+ break;
+
+ CLEAR_TYPE(INT32 , int32 );
+ CLEAR_TYPE(INT64 , int64 );
+ CLEAR_TYPE(UINT32, uint32);
+ CLEAR_TYPE(UINT64, uint64);
+ CLEAR_TYPE(FLOAT , float );
+ CLEAR_TYPE(DOUBLE, double);
+ CLEAR_TYPE(BOOL , bool );
+#undef CLEAR_TYPE
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ *MutableRaw<int>(field) = field->default_value_enum()->number();
+ break;
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ const string* default_ptr = DefaultRaw<const string*>(field);
+ string** value = MutableRaw<string*>(field);
+ if (*value != default_ptr) {
+ if (field->has_default_value()) {
+ (*value)->assign(field->default_value_string());
+ } else {
+ (*value)->clear();
+ }
+ }
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ (*MutableRaw<Message*>(field))->Clear();
+ break;
+ }
+ }
+ } else {
+ MutableRaw<GenericRepeatedField>(field)->GenericClear();
+ }
+}
+
+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();
+ }
+};
+} // namespace
+
+void GeneratedMessageReflection::ListFields(
+ vector<const FieldDescriptor*>* output) const {
+ output->clear();
+
+ // Optimization: The default instance never has any fields set.
+ if (base_ == default_base_) return;
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->is_repeated()) {
+ if (GetRaw<GenericRepeatedField>(field).GenericSize() > 0) {
+ output->push_back(field);
+ }
+ } else {
+ if (HasBit(field)) {
+ output->push_back(field);
+ }
+ }
+ }
+
+ if (extensions_ != NULL) {
+ extensions_->AppendToList(output);
+ }
+
+ // ListFields() must sort output by field number.
+ sort(output->begin(), output->end(), FieldNumberSorter());
+}
+
+// -------------------------------------------------------------------
+
+#undef DEFINE_PRIMITIVE_ACCESSORS
+#define DEFINE_PRIMITIVE_ACCESSORS(TYPENAME, TYPE, PASSTYPE, CPPTYPE) \
+ PASSTYPE GeneratedMessageReflection::Get##TYPENAME( \
+ const FieldDescriptor* field) const { \
+ USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE); \
+ if (field->is_extension()) { \
+ return extensions_->Get##TYPENAME(field->number()); \
+ } else { \
+ return GetField<TYPE>(field); \
+ } \
+ } \
+ \
+ void GeneratedMessageReflection::Set##TYPENAME( \
+ const FieldDescriptor* field, PASSTYPE value) { \
+ USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \
+ if (field->is_extension()) { \
+ return extensions_->Set##TYPENAME(field->number(), value); \
+ } else { \
+ SetField<TYPE>(field, value); \
+ } \
+ } \
+ \
+ PASSTYPE GeneratedMessageReflection::GetRepeated##TYPENAME( \
+ const FieldDescriptor* field, int index) const { \
+ USAGE_CHECK_ALL(GetRepeated##TYPENAME, REPEATED, CPPTYPE); \
+ if (field->is_extension()) { \
+ return extensions_->GetRepeated##TYPENAME(field->number(), index); \
+ } else { \
+ return GetRepeatedField<TYPE>(field, index); \
+ } \
+ } \
+ \
+ void GeneratedMessageReflection::SetRepeated##TYPENAME( \
+ const FieldDescriptor* field, int index, PASSTYPE value) { \
+ USAGE_CHECK_ALL(SetRepeated##TYPENAME, REPEATED, CPPTYPE); \
+ if (field->is_extension()) { \
+ extensions_->SetRepeated##TYPENAME(field->number(), index, value); \
+ } else { \
+ SetRepeatedField<TYPE>(field, index, value); \
+ } \
+ } \
+ \
+ void GeneratedMessageReflection::Add##TYPENAME( \
+ const FieldDescriptor* field, PASSTYPE value) { \
+ USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \
+ if (field->is_extension()) { \
+ extensions_->Add##TYPENAME(field->number(), value); \
+ } else { \
+ AddField<TYPE>(field, value); \
+ } \
+ }
+
+DEFINE_PRIMITIVE_ACCESSORS(Int32 , int32 , int32 , INT32 )
+DEFINE_PRIMITIVE_ACCESSORS(Int64 , int64 , int64 , INT64 )
+DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32, uint32, UINT32)
+DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64, uint64, 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
+
+// -------------------------------------------------------------------
+
+string GeneratedMessageReflection::GetString(
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(GetString, SINGULAR, STRING);
+ if (field->is_extension()) {
+ return extensions_->GetString(field->number());
+ } else {
+ return *GetField<const string*>(field);
+ }
+}
+
+const string& GeneratedMessageReflection::GetStringReference(
+ const FieldDescriptor* field, string* scratch) const {
+ USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING);
+ if (field->is_extension()) {
+ return extensions_->GetString(field->number());
+ } else {
+ return *GetField<const string*>(field);
+ }
+}
+
+
+void GeneratedMessageReflection::SetString(
+ const FieldDescriptor* field, const string& value) {
+ USAGE_CHECK_ALL(SetString, SINGULAR, STRING);
+ if (field->is_extension()) {
+ return extensions_->SetString(field->number(), value);
+ } else {
+ string** ptr = MutableField<string*>(field);
+ if (*ptr == DefaultRaw<const string*>(field)) {
+ *ptr = new string(value);
+ } else {
+ (*ptr)->assign(value);
+ }
+ }
+}
+
+
+string GeneratedMessageReflection::GetRepeatedString(
+ const FieldDescriptor* field, int index) const {
+ USAGE_CHECK_ALL(GetRepeatedString, REPEATED, STRING);
+ if (field->is_extension()) {
+ return extensions_->GetRepeatedString(field->number(), index);
+ } else {
+ return GetRepeatedField<string>(field, index);
+ }
+}
+
+const string& GeneratedMessageReflection::GetRepeatedStringReference(
+ const FieldDescriptor* field, int index, string* scratch) const {
+ USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING);
+ if (field->is_extension()) {
+ return extensions_->GetRepeatedString(field->number(), index);
+ } else {
+ return GetRepeatedField<string>(field, index);
+ }
+}
+
+
+void GeneratedMessageReflection::SetRepeatedString(
+ const FieldDescriptor* field, int index, const string& value) {
+ USAGE_CHECK_ALL(SetRepeatedString, REPEATED, STRING);
+ if (field->is_extension()) {
+ extensions_->SetRepeatedString(field->number(), index, value);
+ } else {
+ SetRepeatedField<string>(field, index, value);
+ }
+}
+
+
+void GeneratedMessageReflection::AddString(
+ const FieldDescriptor* field, const string& value) {
+ USAGE_CHECK_ALL(AddString, REPEATED, STRING);
+ if (field->is_extension()) {
+ extensions_->AddString(field->number(), value);
+ } else {
+ AddField<string>(field, value);
+ }
+}
+
+
+// -------------------------------------------------------------------
+
+const EnumValueDescriptor* GeneratedMessageReflection::GetEnum(
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(GetEnum, SINGULAR, ENUM);
+
+ int value;
+ if (field->is_extension()) {
+ value = extensions_->GetEnum(field->number());
+ } else {
+ value = GetField<int>(field);
+ }
+ const EnumValueDescriptor* result =
+ field->enum_type()->FindValueByNumber(value);
+ GOOGLE_CHECK(result != NULL);
+ return result;
+}
+
+void GeneratedMessageReflection::SetEnum(const FieldDescriptor* field,
+ const EnumValueDescriptor* value) {
+ USAGE_CHECK_ALL(SetEnum, SINGULAR, ENUM);
+ USAGE_CHECK_ENUM_VALUE(SetEnum);
+
+ if (field->is_extension()) {
+ extensions_->SetEnum(field->number(), value->number());
+ } else {
+ SetField<int>(field, value->number());
+ }
+}
+
+const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum(
+ const FieldDescriptor* field, int index) const {
+ USAGE_CHECK_ALL(GetRepeatedEnum, REPEATED, ENUM);
+
+ int value;
+ if (field->is_extension()) {
+ value = extensions_->GetRepeatedEnum(field->number(), index);
+ } else {
+ value = GetRepeatedField<int>(field, index);
+ }
+ const EnumValueDescriptor* result =
+ field->enum_type()->FindValueByNumber(value);
+ GOOGLE_CHECK(result != NULL);
+ return result;
+}
+
+void GeneratedMessageReflection::SetRepeatedEnum(
+ const FieldDescriptor* field, int index,
+ const EnumValueDescriptor* value) {
+ USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM);
+ USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum);
+
+ if (field->is_extension()) {
+ extensions_->SetRepeatedEnum(field->number(), index, value->number());
+ } else {
+ SetRepeatedField<int>(field, index, value->number());
+ }
+}
+
+void GeneratedMessageReflection::AddEnum(const FieldDescriptor* field,
+ const EnumValueDescriptor* value) {
+ USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM);
+ USAGE_CHECK_ENUM_VALUE(AddEnum);
+
+ if (field->is_extension()) {
+ extensions_->AddEnum(field->number(), value->number());
+ } else {
+ AddField<int>(field, value->number());
+ }
+}
+
+// -------------------------------------------------------------------
+
+const Message& GeneratedMessageReflection::GetMessage(
+ const FieldDescriptor* field) const {
+ USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
+
+ if (field->is_extension()) {
+ return extensions_->GetMessage(field->number());
+ } else {
+ const Message* result = GetRaw<const Message*>(field);
+ if (result == NULL) {
+ result = DefaultRaw<const Message*>(field);
+ }
+ return *result;
+ }
+}
+
+Message* GeneratedMessageReflection::MutableMessage(
+ const FieldDescriptor* field) {
+ USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+
+ if (field->is_extension()) {
+ return extensions_->MutableMessage(field->number());
+ } else {
+ Message** result = MutableField<Message*>(field);
+ if (*result == NULL) {
+ const Message* default_message = DefaultRaw<const Message*>(field);
+ *result = default_message->New();
+ (*result)->CopyFrom(*default_message);
+ }
+ return *result;
+ }
+}
+
+const Message& GeneratedMessageReflection::GetRepeatedMessage(
+ const FieldDescriptor* field, int index) const {
+ USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
+
+ if (field->is_extension()) {
+ return extensions_->GetRepeatedMessage(field->number(), index);
+ } else {
+ return GetRepeatedField<Message>(field, index);
+ }
+}
+
+Message* GeneratedMessageReflection::MutableRepeatedMessage(
+ const FieldDescriptor* field, int index) {
+ USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE);
+
+ if (field->is_extension()) {
+ return extensions_->MutableRepeatedMessage(field->number(), index);
+ } else {
+ return MutableRepeatedField<Message>(field, index);
+ }
+}
+
+Message* GeneratedMessageReflection::AddMessage(const FieldDescriptor* field) {
+ USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE);
+
+ if (field->is_extension()) {
+ return extensions_->AddMessage(field->number());
+ } else {
+ return AddField<Message>(field);
+ }
+}
+
+// -------------------------------------------------------------------
+
+const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName(
+ const string& name) const {
+ if (extensions_ == NULL) return NULL;
+ return extensions_->FindKnownExtensionByName(name);
+}
+
+const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByNumber(
+ int number) const {
+ if (extensions_ == NULL) return NULL;
+ return extensions_->FindKnownExtensionByNumber(number);
+}
+
+// ===================================================================
+// Some private helpers.
+
+// These simple template accessors obtain pointers (or references) to
+// the given field.
+template <typename Type>
+inline const Type& GeneratedMessageReflection::GetRaw(
+ const FieldDescriptor* field) const {
+ const void* ptr = reinterpret_cast<const uint8*>(base_) +
+ offsets_[field->index()];
+ return *reinterpret_cast<const Type*>(ptr);
+}
+
+template <typename Type>
+inline Type* GeneratedMessageReflection::MutableRaw(
+ const FieldDescriptor* field) {
+ void* ptr = reinterpret_cast<uint8*>(base_) + offsets_[field->index()];
+ return reinterpret_cast<Type*>(ptr);
+}
+
+template <typename Type>
+inline const Type& GeneratedMessageReflection::DefaultRaw(
+ const FieldDescriptor* field) const {
+ const void* ptr = reinterpret_cast<const uint8*>(default_base_) +
+ offsets_[field->index()];
+ return *reinterpret_cast<const Type*>(ptr);
+}
+
+// Simple accessors for manipulating has_bits_.
+inline bool GeneratedMessageReflection::HasBit(
+ const FieldDescriptor* field) const {
+ return has_bits_[field->index() / 32] & (1 << (field->index() % 32));
+}
+
+inline void GeneratedMessageReflection::SetBit(
+ const FieldDescriptor* field) {
+ has_bits_[field->index() / 32] |= (1 << (field->index() % 32));
+}
+
+inline void GeneratedMessageReflection::ClearBit(
+ const FieldDescriptor* field) {
+ has_bits_[field->index() / 32] &= ~(1 << (field->index() % 32));
+}
+
+// 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>
+inline const Type& GeneratedMessageReflection::GetField(
+ const FieldDescriptor* field) const {
+ return GetRaw<Type>(field);
+}
+
+template <typename Type>
+inline void GeneratedMessageReflection::SetField(
+ const FieldDescriptor* field, const Type& value) {
+ *MutableRaw<Type>(field) = value;
+ SetBit(field);
+}
+
+template <typename Type>
+inline Type* GeneratedMessageReflection::MutableField(
+ const FieldDescriptor* field) {
+ SetBit(field);
+ return MutableRaw<Type>(field);
+}
+
+template <typename Type>
+inline const Type& GeneratedMessageReflection::GetRepeatedField(
+ const FieldDescriptor* field, int index) const {
+ return *reinterpret_cast<const Type*>(
+ GetRaw<GenericRepeatedField>(field).GenericGet(index));
+}
+
+template <typename Type>
+inline void GeneratedMessageReflection::SetRepeatedField(
+ const FieldDescriptor* field, int index, const Type& value) {
+ GenericRepeatedField* repeated = MutableRaw<GenericRepeatedField>(field);
+ *reinterpret_cast<Type*>(repeated->GenericMutable(index)) = value;
+}
+
+template <typename Type>
+inline Type* GeneratedMessageReflection::MutableRepeatedField(
+ const FieldDescriptor* field, int index) {
+ GenericRepeatedField* repeated = MutableRaw<GenericRepeatedField>(field);
+ return reinterpret_cast<Type*>(repeated->GenericMutable(index));
+}
+
+template <typename Type>
+inline void GeneratedMessageReflection::AddField(
+ const FieldDescriptor* field, const Type& value) {
+ GenericRepeatedField* repeated = MutableRaw<GenericRepeatedField>(field);
+ *reinterpret_cast<Type*>(repeated->GenericAdd()) = value;
+}
+
+template <typename Type>
+inline Type* GeneratedMessageReflection::AddField(
+ const FieldDescriptor* field) {
+ GenericRepeatedField* repeated = MutableRaw<GenericRepeatedField>(field);
+ return reinterpret_cast<Type*>(repeated->GenericAdd());
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
new file mode 100644
index 00000000..579d6abe
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -0,0 +1,300 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <vector>
+#include <google/protobuf/message.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Generated code needs this to have been forward-declared. Easier to do it
+// here than to print it inside every .pb.h file.
+namespace google {
+namespace protobuf { class EnumDescriptor; }
+
+namespace protobuf {
+namespace internal {
+
+// Defined in this file.
+class GeneratedMessageReflection;
+
+// Defined in other files.
+class ExtensionSet; // extension_set.h
+
+// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use
+// by generated code. This class is just a big hack that reduces code
+// size.
+//
+// A GeneratedMessageReflection is an implementation of Message::Reflection
+// which expects all fields to be backed by simple variables located in
+// memory. The locations are given using a base pointer and a set of
+// offsets.
+//
+// It is required that the user represents fields of each type in a standard
+// way, so that GeneratedMessageReflection can cast the void* pointer to
+// the appropriate type. For primitive fields and string fields, each field
+// should be represented using the obvious C++ primitive type. Enums and
+// Messages are different:
+// - Singular Message fields are stored as a pointer to a Message. These
+// should start out NULL, except for in the default instance where they
+// should start out pointing to other default instances.
+// - Enum fields are stored as an int. This int must always contain
+// a valid value, such that EnumDescriptor::FindValueByNumber() would
+// not return NULL.
+// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields
+// of whatever type the individual field would be. Strings and
+// Messages use RepeatedPtrFields while everything else uses
+// RepeatedFields.
+class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Message::Reflection {
+ public:
+ // Constructs a GeneratedMessageReflection.
+ // Parameters:
+ // descriptor: The descriptor for the message type being implemented.
+ // base: Pointer to the location where the message object is
+ // stored.
+ // default_base: Pointer to the location where the message's default
+ // instance is stored. 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 bits giving the byte offsets, relative to
+ // "base" and "default_base", of each field. These can
+ // be computed at compile time using the
+ // GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined
+ // below.
+ // has_bits: 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))
+ // extensions: The ExtensionSet for this message, or NULL if the
+ // message type has no extension ranges.
+ GeneratedMessageReflection(const Descriptor* descriptor,
+ void* base, const void* default_base,
+ const int offsets[], uint32 has_bits[],
+ ExtensionSet* extensions);
+ ~GeneratedMessageReflection();
+
+ inline const UnknownFieldSet& unknown_fields() const {
+ return unknown_fields_;
+ }
+ inline UnknownFieldSet* mutable_unknown_fields() {
+ return &unknown_fields_;
+ }
+
+ // implements Message::Reflection ----------------------------------
+
+ const UnknownFieldSet& GetUnknownFields() const;
+ UnknownFieldSet* MutableUnknownFields();
+
+ bool HasField(const FieldDescriptor* field) const;
+ int FieldSize(const FieldDescriptor* field) const;
+ void ClearField(const FieldDescriptor* field);
+ void ListFields(vector<const FieldDescriptor*>* output) const;
+
+ int32 GetInt32 (const FieldDescriptor* field) const;
+ int64 GetInt64 (const FieldDescriptor* field) const;
+ uint32 GetUInt32(const FieldDescriptor* field) const;
+ uint64 GetUInt64(const FieldDescriptor* field) const;
+ float GetFloat (const FieldDescriptor* field) const;
+ double GetDouble(const FieldDescriptor* field) const;
+ bool GetBool (const FieldDescriptor* field) const;
+ string GetString(const FieldDescriptor* field) const;
+ const string& GetStringReference(const FieldDescriptor* field,
+ string* scratch) const;
+ const EnumValueDescriptor* GetEnum(const FieldDescriptor* field) const;
+ const Message& GetMessage(const FieldDescriptor* field) const;
+
+ void SetInt32 (const FieldDescriptor* field, int32 value);
+ void SetInt64 (const FieldDescriptor* field, int64 value);
+ void SetUInt32(const FieldDescriptor* field, uint32 value);
+ void SetUInt64(const FieldDescriptor* field, uint64 value);
+ void SetFloat (const FieldDescriptor* field, float value);
+ void SetDouble(const FieldDescriptor* field, double value);
+ void SetBool (const FieldDescriptor* field, bool value);
+ void SetString(const FieldDescriptor* field,
+ const string& value);
+ void SetEnum (const FieldDescriptor* field,
+ const EnumValueDescriptor* value);
+ Message* MutableMessage(const FieldDescriptor* field);
+
+ int32 GetRepeatedInt32 (const FieldDescriptor* field, int index) const;
+ int64 GetRepeatedInt64 (const FieldDescriptor* field, int index) const;
+ uint32 GetRepeatedUInt32(const FieldDescriptor* field, int index) const;
+ uint64 GetRepeatedUInt64(const FieldDescriptor* field, int index) const;
+ float GetRepeatedFloat (const FieldDescriptor* field, int index) const;
+ double GetRepeatedDouble(const FieldDescriptor* field, int index) const;
+ bool GetRepeatedBool (const FieldDescriptor* field, int index) const;
+ string GetRepeatedString(const FieldDescriptor* field, int index) const;
+ const string& GetRepeatedStringReference(const FieldDescriptor* field,
+ int index, string* scratch) const;
+ const EnumValueDescriptor* GetRepeatedEnum(const FieldDescriptor* field,
+ int index) const;
+ const Message& GetRepeatedMessage(const FieldDescriptor* field,
+ int index) const;
+
+ // Set the value of a field.
+ void SetRepeatedInt32 (const FieldDescriptor* field, int index, int32 value);
+ void SetRepeatedInt64 (const FieldDescriptor* field, int index, int64 value);
+ void SetRepeatedUInt32(const FieldDescriptor* field, int index, uint32 value);
+ void SetRepeatedUInt64(const FieldDescriptor* field, int index, uint64 value);
+ void SetRepeatedFloat (const FieldDescriptor* field, int index, float value);
+ void SetRepeatedDouble(const FieldDescriptor* field, int index, double value);
+ void SetRepeatedBool (const FieldDescriptor* field, int index, bool value);
+ void SetRepeatedString(const FieldDescriptor* field, int index,
+ const string& value);
+ void SetRepeatedEnum (const FieldDescriptor* field, int index,
+ const EnumValueDescriptor* value);
+ // Get a mutable pointer to a field with a message type.
+ Message* MutableRepeatedMessage(const FieldDescriptor* field, int index);
+
+ void AddInt32 (const FieldDescriptor* field, int32 value);
+ void AddInt64 (const FieldDescriptor* field, int64 value);
+ void AddUInt32(const FieldDescriptor* field, uint32 value);
+ void AddUInt64(const FieldDescriptor* field, uint64 value);
+ void AddFloat (const FieldDescriptor* field, float value);
+ void AddDouble(const FieldDescriptor* field, double value);
+ void AddBool (const FieldDescriptor* field, bool value);
+ void AddString(const FieldDescriptor* field, const string& value);
+ void AddEnum(const FieldDescriptor* field, const EnumValueDescriptor* value);
+ Message* AddMessage(const FieldDescriptor* field);
+
+ const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
+ const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
+
+ private:
+ friend class GeneratedMessage;
+
+ const Descriptor* descriptor_;
+ void* base_;
+ const void* default_base_;
+ const int* offsets_;
+
+ // TODO(kenton): These two pointers just point back into the message object.
+ // We could save space by removing them and using offsets instead.
+ uint32* has_bits_;
+ ExtensionSet* extensions_;
+
+ // We put this directly in the GeneratedMessageReflection because every
+ // message class needs it, and if we don't find any unknown fields, it
+ // takes up only one pointer of space.
+ UnknownFieldSet unknown_fields_;
+
+ template <typename Type>
+ inline const Type& GetRaw(const FieldDescriptor* field) const;
+ template <typename Type>
+ inline Type* MutableRaw(const FieldDescriptor* field);
+ template <typename Type>
+ inline const Type& DefaultRaw(const FieldDescriptor* field) const;
+ inline const Message* GetMessagePrototype(const FieldDescriptor* field) const;
+
+ inline bool HasBit(const FieldDescriptor* field) const;
+ inline void SetBit(const FieldDescriptor* field);
+ inline void ClearBit(const FieldDescriptor* field);
+
+ template <typename Type>
+ inline const Type& GetField(const FieldDescriptor* field) const;
+ template <typename Type>
+ inline void SetField(const FieldDescriptor* field, const Type& value);
+ template <typename Type>
+ inline Type* MutableField(const FieldDescriptor* field);
+ template <typename Type>
+ inline const Type& GetRepeatedField(const FieldDescriptor* field,
+ int index) const;
+ template <typename Type>
+ inline void SetRepeatedField(const FieldDescriptor* field, int index,
+ const Type& value);
+ template <typename Type>
+ inline Type* MutableRepeatedField(const FieldDescriptor* field, int index);
+ template <typename Type>
+ inline void AddField(const FieldDescriptor* field, const Type& value);
+ template <typename Type>
+ inline Type* AddField(const FieldDescriptor* field);
+
+ int GetExtensionNumberOrDie(const Descriptor* type) const;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
+};
+
+// 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.
+//
+// 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 GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
+ (reinterpret_cast<const char*>( \
+ &reinterpret_cast<const TYPE*>(16)->FIELD) - \
+ reinterpret_cast<const char*>(16))
+
+// There are some places in proto2 where dynamic_cast would be useful as an
+// optimization. For example, take Message::MergeFrom(const Message& other).
+// For a given generated message FooMessage, we generate these two methods:
+// void MergeFrom(const FooMessage& other);
+// void MergeFrom(const Message& other);
+// The former method can be implemented directly in terms of FooMessage's
+// inline accessors, but the latter method must work with the reflection
+// interface. However, if the parameter to the latter method is actually of
+// type FooMessage, then we'd like to be able to just call the other method
+// as an optimization. So, we use dynamic_cast to check this.
+//
+// That said, dynamic_cast requires RTTI, which many people like to disable
+// for performance and code size reasons. When RTTI is not available, we
+// still need to produce correct results. So, in this case we have to fall
+// back to using reflection, which is what we would have done anyway if the
+// objects were not of the exact same class.
+//
+// dynamic_cast_if_available() implements this logic. If RTTI is
+// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns
+// NULL.
+//
+// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
+// On MSVC, this should be detected automatically.
+template<typename To, typename From>
+inline To dynamic_cast_if_available(From from) {
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
+ return NULL;
+#else
+ return dynamic_cast<To>(from);
+#endif
+}
+
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..bde7fac7
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -0,0 +1,251 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/descriptor.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+const FieldDescriptor* F(const string& name) {
+ const FieldDescriptor* result =
+ unittest::TestAllTypes::descriptor()->FindFieldByName(name);
+ GOOGLE_CHECK(result != NULL);
+ 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.GetReflection());
+
+ const Message::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(F("optionalgroup")));
+ EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
+ &reflection.GetMessage(F("optional_nested_message")));
+ EXPECT_EQ(&unittest::ForeignMessage::default_instance(),
+ &reflection.GetMessage(F("optional_foreign_message")));
+ EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
+ &reflection.GetMessage(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.GetReflection());
+ TestUtil::ExpectAllFieldsSet(message);
+ reflection_tester.ExpectAllFieldsSetViaReflection(*message.GetReflection());
+
+ reflection_tester.ModifyRepeatedFieldsViaReflection(message.GetReflection());
+ 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 Message::Reflection& reflection = *message.GetReflection();
+ string scratch;
+
+ EXPECT_EQ(&message.optional_string(),
+ &reflection.GetStringReference(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(F("repeated_string"), 0, &scratch))
+ << "For simple string fields, GetRepeatedStringReference() should return "
+ "a reference to the underlying string.";
+}
+
+
+TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) {
+ // Check that after setting all fields and then clearing, getting an
+ // embedded message does NOT return the default instance.
+ unittest::TestAllTypes message;
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+
+ TestUtil::SetAllFields(&message);
+ message.Clear();
+
+ const Message::Reflection& reflection = *message.GetReflection();
+
+ EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(),
+ &reflection.GetMessage(F("optionalgroup")));
+ EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
+ &reflection.GetMessage(F("optional_nested_message")));
+ EXPECT_NE(&unittest::ForeignMessage::default_instance(),
+ &reflection.GetMessage(F("optional_foreign_message")));
+ EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
+ &reflection.GetMessage(F("optional_import_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.GetReflection());
+ TestUtil::ExpectAllExtensionsSet(message);
+ reflection_tester.ExpectAllFieldsSetViaReflection(*message.GetReflection());
+
+ reflection_tester.ModifyRepeatedFieldsViaReflection(message.GetReflection());
+ TestUtil::ExpectRepeatedExtensionsModified(message);
+}
+
+TEST(GeneratedMessageReflectionTest, FindExtensionTypeByNumber) {
+ const Message::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) == NULL);
+
+ // Extensions of TestAllExtensions should not show up as extensions of
+ // other types.
+ EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()->
+ FindKnownExtensionByNumber(extension1->number()) == NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) {
+ const Message::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") == NULL);
+
+ // Extensions of TestAllExtensions should not show up as extensions of
+ // other types.
+ EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()->
+ FindKnownExtensionByName(extension1->full_name()) == NULL);
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST(GeneratedMessageReflectionTest, UsageErrors) {
+ unittest::TestAllTypes message;
+ Message::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(descriptor->FindFieldByName("optional_int64")),
+ "Protocol Buffer reflection usage error:\n"
+ " Method : google::protobuf::Message::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(descriptor->FindFieldByName("repeated_int32")),
+ "Protocol Buffer reflection usage error:\n"
+ " Method : google::protobuf::Message::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(
+ unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
+ "Protocol Buffer reflection usage error:\n"
+ " Method : google::protobuf::Message::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(
+ unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
+ "Protocol Buffer reflection usage error:\n"
+ " Method : google::protobuf::Message::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 // GTEST_HAS_DEATH_TEST
+
+
+} // 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 00000000..58c44dc1
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -0,0 +1,757 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <stack>
+#include <limits.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stl_util-inl.h>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+namespace {
+
+static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB
+
+static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB
+static const int kDefaultRecursionLimit = 64;
+
+static const int kMaxVarintBytes = 10;
+static const int kMaxVarint32Bytes = 5;
+
+
+} // namespace
+
+// CodedInputStream ==================================================
+
+CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
+ : input_(input),
+ buffer_(NULL),
+ buffer_size_(0),
+ total_bytes_read_(0),
+ overflow_bytes_(0),
+
+ last_tag_(0),
+ legitimate_message_end_(false),
+
+ aliasing_enabled_(false),
+
+ current_limit_(INT_MAX),
+ buffer_size_after_limit_(0),
+
+ total_bytes_limit_(kDefaultTotalBytesLimit),
+ total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
+
+ recursion_depth_(0),
+ recursion_limit_(kDefaultRecursionLimit) {
+}
+
+CodedInputStream::~CodedInputStream() {
+ int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_;
+ if (backup_bytes > 0) {
+ // We still have bytes left over from the last buffer. Back up over
+ // them.
+ input_->BackUp(backup_bytes);
+ }
+}
+
+
+inline void CodedInputStream::RecomputeBufferLimits() {
+ buffer_size_ += buffer_size_after_limit_;
+ int closest_limit = 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_size_ -= 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 = total_bytes_read_ -
+ (buffer_size_ + buffer_size_after_limit_);
+
+ Limit old_limit = current_limit_;
+
+ // security: byte_limit is possibly evil, so check for negative values
+ // and overflow.
+ if (byte_limit >= 0 &&
+ byte_limit <= INT_MAX - current_position) {
+ current_limit_ = current_position + byte_limit;
+ } else {
+ // Negative or overflow.
+ current_limit_ = INT_MAX;
+ }
+
+ // We need to enforce all limits, not just the new one, so if the previous
+ // limit was before the new requested limit, we continue to enforce the
+ // previous limit.
+ current_limit_ = min(current_limit_, old_limit);
+
+ 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;
+}
+
+int CodedInputStream::BytesUntilLimit() {
+ if (current_limit_ == INT_MAX) return -1;
+ int current_position = total_bytes_read_ -
+ (buffer_size_ + buffer_size_after_limit_);
+
+ return current_limit_ - current_position;
+}
+
+void CodedInputStream::SetTotalBytesLimit(
+ int total_bytes_limit, int warning_threshold) {
+ // Make sure the limit isn't already past, since this could confuse other
+ // code.
+ int current_position = total_bytes_read_ -
+ (buffer_size_ + buffer_size_after_limit_);
+ total_bytes_limit_ = max(current_position, total_bytes_limit);
+ total_bytes_warning_threshold_ = warning_threshold;
+ RecomputeBufferLimits();
+}
+
+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 google/protobuf/io/coded_stream.h.";
+}
+
+bool CodedInputStream::Skip(int count) {
+ if (count < 0) return false; // security: count is often user-supplied
+
+ if (count <= buffer_size_) {
+ // Just skipping within the current buffer. Easy.
+ Advance(count);
+ return true;
+ }
+
+ if (buffer_size_after_limit_ > 0) {
+ // We hit a limit inside this buffer. Advance to the limit and fail.
+ Advance(buffer_size_);
+ return false;
+ }
+
+ count -= buffer_size_;
+ buffer_ = NULL;
+ buffer_size_ = 0;
+
+ // Make sure this skip doesn't try to skip past the current limit.
+ int closest_limit = 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.
+ total_bytes_read_ = closest_limit;
+ input_->Skip(bytes_until_limit);
+ return false;
+ }
+
+ total_bytes_read_ += count;
+ return input_->Skip(count);
+}
+
+bool CodedInputStream::ReadRaw(void* buffer, int size) {
+ while (buffer_size_ < size) {
+ // Reading past end of buffer. Copy what we have, then refresh.
+ memcpy(buffer, buffer_, buffer_size_);
+ buffer = reinterpret_cast<uint8*>(buffer) + buffer_size_;
+ size -= buffer_size_;
+ if (!Refresh()) return false;
+ }
+
+ memcpy(buffer, buffer_, size);
+ Advance(size);
+
+ return true;
+}
+
+bool CodedInputStream::ReadString(string* buffer, int size) {
+ if (size < 0) return false; // security: size is often user-supplied
+
+ if (!buffer->empty()) {
+ buffer->clear();
+ }
+
+ if (size < buffer_size_) {
+ STLStringResizeUninitialized(buffer, size);
+ memcpy((uint8*)buffer->data(), buffer_, size);
+ Advance(size);
+ return true;
+ }
+
+ while (buffer_size_ < size) {
+ // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
+ if (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_), buffer_size_);
+ }
+ size -= buffer_size_;
+ if (!Refresh()) return false;
+ }
+
+ buffer->append(reinterpret_cast<const char*>(buffer_), size);
+ Advance(size);
+
+ return true;
+}
+
+
+bool CodedInputStream::ReadLittleEndian32(uint32* value) {
+ uint8 bytes[sizeof(*value)];
+
+ const uint8* ptr;
+ if (buffer_size_ >= 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;
+ }
+
+ *value = (static_cast<uint32>(ptr[0]) ) |
+ (static_cast<uint32>(ptr[1]) << 8) |
+ (static_cast<uint32>(ptr[2]) << 16) |
+ (static_cast<uint32>(ptr[3]) << 24);
+ return true;
+}
+
+bool CodedInputStream::ReadLittleEndian64(uint64* value) {
+ uint8 bytes[sizeof(*value)];
+
+ const uint8* ptr;
+ if (buffer_size_ >= 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;
+ }
+
+ uint32 part0 = (static_cast<uint32>(ptr[0]) ) |
+ (static_cast<uint32>(ptr[1]) << 8) |
+ (static_cast<uint32>(ptr[2]) << 16) |
+ (static_cast<uint32>(ptr[3]) << 24);
+ uint32 part1 = (static_cast<uint32>(ptr[4]) ) |
+ (static_cast<uint32>(ptr[5]) << 8) |
+ (static_cast<uint32>(ptr[6]) << 16) |
+ (static_cast<uint32>(ptr[7]) << 24);
+ *value = static_cast<uint64>(part0) |
+ (static_cast<uint64>(part1) << 32);
+ return true;
+}
+
+bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
+ if (buffer_size_ >= kMaxVarintBytes ||
+ // Optimization: If the varint ends at exactly the end of the buffer,
+ // we can detect that and still use the fast path.
+ (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) {
+ // 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.
+ const uint8* ptr = buffer_;
+ uint32 b;
+ uint32 result;
+
+ b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
+ b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
+ b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
+ b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
+ b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
+
+ // 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 false;
+
+ done:
+ Advance(ptr - buffer_);
+ *value = result;
+ return true;
+
+ } else {
+ // Optimization: If we're at a limit, detect that quickly. (This is
+ // common when reading tags.)
+ while (buffer_size_ == 0) {
+ // Detect cases where we definitely hit a byte limit without calling
+ // Refresh().
+ if (// If we hit a limit, buffer_size_after_limit_ will be non-zero.
+ buffer_size_after_limit_ > 0 &&
+ // 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 false;
+ }
+
+ // 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 false;
+ }
+ }
+
+ // Slow path: Just do a 64-bit read.
+ uint64 result;
+ if (!ReadVarint64(&result)) return false;
+ *value = (uint32)result;
+ return true;
+ }
+}
+
+bool CodedInputStream::ReadVarint64(uint64* value) {
+ if (buffer_size_ >= kMaxVarintBytes ||
+ // Optimization: If the varint ends at exactly the end of the buffer,
+ // we can detect that and still use the fast path.
+ (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) {
+ // 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.
+
+ const uint8* ptr = buffer_;
+ uint32 b;
+
+ // Splitting into 32-bit pieces gives better performance on 32-bit
+ // processors.
+ uint32 part0 = 0, part1 = 0, part2 = 0;
+
+ b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
+ b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
+
+ // We have overrun the maximum size of a varint (10 bytes). The data
+ // must be corrupt.
+ return false;
+
+ done:
+ Advance(ptr - buffer_);
+ *value = (static_cast<uint64>(part0) ) |
+ (static_cast<uint64>(part1) << 28) |
+ (static_cast<uint64>(part2) << 56);
+ return true;
+
+ } else {
+ // 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 result = 0;
+ int count = 0;
+ uint32 b;
+
+ do {
+ if (count == kMaxVarintBytes) return false;
+ while (buffer_size_ == 0) {
+ if (!Refresh()) return false;
+ }
+ b = *buffer_;
+ result |= static_cast<uint64>(b & 0x7F) << (7 * count);
+ Advance(1);
+ ++count;
+ } while(b & 0x80);
+
+ *value = result;
+ return true;
+ }
+}
+
+bool CodedInputStream::Refresh() {
+ if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0) {
+ // We've hit a limit. Stop.
+ buffer_ += buffer_size_;
+ buffer_size_ = 0;
+
+ 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;
+ }
+
+ if (total_bytes_warning_threshold_ >= 0 &&
+ total_bytes_read_ >= total_bytes_warning_threshold_) {
+ GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
+ "message turns out to be larger than "
+ << total_bytes_limit_ << " bytes, parsing will be halted "
+ "for security reasons. To increase the limit (or to "
+ "disable these warnings), see "
+ "CodedInputStream::SetTotalBytesLimit() in "
+ "google/protobuf/io/coded_stream.h.";
+
+ // Don't warn again for this stream.
+ total_bytes_warning_threshold_ = -1;
+ }
+
+ const void* void_buffer;
+ if (input_->Next(&void_buffer, &buffer_size_)) {
+ buffer_ = reinterpret_cast<const uint8*>(void_buffer);
+ GOOGLE_CHECK_GE(buffer_size_, 0);
+
+ if (total_bytes_read_ <= INT_MAX - buffer_size_) {
+ total_bytes_read_ += buffer_size_;
+ } else {
+ // Overflow. Reset buffer_size_ 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_size_ -= overflow_bytes_;
+ total_bytes_read_ = INT_MAX;
+ }
+
+ RecomputeBufferLimits();
+ return true;
+ } else {
+ buffer_ = NULL;
+ buffer_size_ = 0;
+ return false;
+ }
+}
+
+// CodedOutputStream =================================================
+
+CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
+ : output_(output),
+ buffer_(NULL),
+ buffer_size_(0),
+ total_bytes_(0) {
+}
+
+CodedOutputStream::~CodedOutputStream() {
+ if (buffer_size_ > 0) {
+ output_->BackUp(buffer_size_);
+ }
+}
+
+bool CodedOutputStream::WriteRaw(const void* data, int size) {
+ while (buffer_size_ < size) {
+ memcpy(buffer_, data, buffer_size_);
+ size -= buffer_size_;
+ data = reinterpret_cast<const uint8*>(data) + buffer_size_;
+ if (!Refresh()) return false;
+ }
+
+ memcpy(buffer_, data, size);
+ Advance(size);
+ return true;
+}
+
+
+bool CodedOutputStream::WriteLittleEndian32(uint32 value) {
+ uint8 bytes[sizeof(value)];
+
+ bool use_fast = buffer_size_ >= sizeof(value);
+ uint8* ptr = use_fast ? buffer_ : bytes;
+
+ ptr[0] = static_cast<uint8>(value );
+ ptr[1] = static_cast<uint8>(value >> 8);
+ ptr[2] = static_cast<uint8>(value >> 16);
+ ptr[3] = static_cast<uint8>(value >> 24);
+
+ if (use_fast) {
+ Advance(sizeof(value));
+ return true;
+ } else {
+ return WriteRaw(bytes, sizeof(value));
+ }
+}
+
+bool CodedOutputStream::WriteLittleEndian64(uint64 value) {
+ uint8 bytes[sizeof(value)];
+
+ uint32 part0 = static_cast<uint32>(value);
+ uint32 part1 = static_cast<uint32>(value >> 32);
+
+ bool use_fast = buffer_size_ >= sizeof(value);
+ uint8* ptr = use_fast ? buffer_ : bytes;
+
+ ptr[0] = static_cast<uint8>(part0 );
+ ptr[1] = static_cast<uint8>(part0 >> 8);
+ ptr[2] = static_cast<uint8>(part0 >> 16);
+ ptr[3] = static_cast<uint8>(part0 >> 24);
+ ptr[4] = static_cast<uint8>(part1 );
+ ptr[5] = static_cast<uint8>(part1 >> 8);
+ ptr[6] = static_cast<uint8>(part1 >> 16);
+ ptr[7] = static_cast<uint8>(part1 >> 24);
+
+ if (use_fast) {
+ Advance(sizeof(value));
+ return true;
+ } else {
+ return WriteRaw(bytes, sizeof(value));
+ }
+}
+
+bool CodedOutputStream::WriteVarint32Fallback(uint32 value) {
+ if (buffer_size_ >= kMaxVarint32Bytes) {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this write won't cross the end, so we can skip the checks.
+ uint8* target = buffer_;
+
+ target[0] = static_cast<uint8>(value | 0x80);
+ if (value >= (1 << 7)) {
+ target[1] = static_cast<uint8>((value >> 7) | 0x80);
+ if (value >= (1 << 14)) {
+ target[2] = static_cast<uint8>((value >> 14) | 0x80);
+ if (value >= (1 << 21)) {
+ target[3] = static_cast<uint8>((value >> 21) | 0x80);
+ if (value >= (1 << 28)) {
+ target[4] = static_cast<uint8>(value >> 28);
+ Advance(5);
+ } else {
+ target[3] &= 0x7F;
+ Advance(4);
+ }
+ } else {
+ target[2] &= 0x7F;
+ Advance(3);
+ }
+ } else {
+ target[1] &= 0x7F;
+ Advance(2);
+ }
+ } else {
+ target[0] &= 0x7F;
+ Advance(1);
+ }
+
+ return true;
+ } else {
+ // Slow path: This write might cross the end of the buffer, so we
+ // compose the bytes first then use WriteRaw().
+ uint8 bytes[kMaxVarint32Bytes];
+ int size = 0;
+ while (value > 0x7F) {
+ bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
+ value >>= 7;
+ }
+ bytes[size++] = static_cast<uint8>(value) & 0x7F;
+ return WriteRaw(bytes, size);
+ }
+}
+
+bool CodedOutputStream::WriteVarint64(uint64 value) {
+ if (buffer_size_ >= kMaxVarintBytes) {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this write won't cross the end, so we can skip the checks.
+ uint8* target = buffer_;
+
+ // Splitting into 32-bit pieces gives better performance on 32-bit
+ // processors.
+ uint32 part0 = static_cast<uint32>(value );
+ uint32 part1 = static_cast<uint32>(value >> 28);
+ uint32 part2 = static_cast<uint32>(value >> 56);
+
+ int size;
+
+ // Here we can't really optimize for small numbers, since the value is
+ // split into three parts. Cheking for numbers < 128, for instance,
+ // would require three comparisons, since you'd have to make sure part1
+ // and part2 are zero. However, if the caller is using 64-bit integers,
+ // it is likely that they expect the numbers to often be very large, so
+ // we probably don't want to optimize for small numbers anyway. Thus,
+ // we end up with a hardcoded binary search tree...
+ if (part2 == 0) {
+ if (part1 == 0) {
+ if (part0 < (1 << 14)) {
+ if (part0 < (1 << 7)) {
+ size = 1; goto size1;
+ } else {
+ size = 2; goto size2;
+ }
+ } else {
+ if (part0 < (1 << 21)) {
+ size = 3; goto size3;
+ } else {
+ size = 4; goto size4;
+ }
+ }
+ } else {
+ if (part1 < (1 << 14)) {
+ if (part1 < (1 << 7)) {
+ size = 5; goto size5;
+ } else {
+ size = 6; goto size6;
+ }
+ } else {
+ if (part1 < (1 << 21)) {
+ size = 7; goto size7;
+ } else {
+ size = 8; goto size8;
+ }
+ }
+ }
+ } else {
+ if (part2 < (1 << 7)) {
+ size = 9; goto size9;
+ } else {
+ size = 10; goto size10;
+ }
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+
+ size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
+ size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
+ size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
+ size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
+ size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
+ size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
+ size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
+ size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
+ size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
+ size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
+
+ target[size-1] &= 0x7F;
+ Advance(size);
+ return true;
+ } else {
+ // Slow path: This write might cross the end of the buffer, so we
+ // compose the bytes first then use WriteRaw().
+ uint8 bytes[kMaxVarintBytes];
+ int size = 0;
+ while (value > 0x7F) {
+ bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
+ value >>= 7;
+ }
+ bytes[size++] = static_cast<uint8>(value) & 0x7F;
+ return WriteRaw(bytes, size);
+ }
+}
+
+bool CodedOutputStream::Refresh() {
+ void* void_buffer;
+ if (output_->Next(&void_buffer, &buffer_size_)) {
+ buffer_ = reinterpret_cast<uint8*>(void_buffer);
+ total_bytes_ += buffer_size_;
+ return true;
+ } else {
+ buffer_ = NULL;
+ buffer_size_ = 0;
+ return false;
+ }
+}
+
+int CodedOutputStream::VarintSize32Fallback(uint32 value) {
+ if (value < (1 << 7)) {
+ return 1;
+ } else if (value < (1 << 14)) {
+ return 2;
+ } else if (value < (1 << 21)) {
+ return 3;
+ } else if (value < (1 << 28)) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+int CodedOutputStream::VarintSize64(uint64 value) {
+ if (value < (1ull << 35)) {
+ if (value < (1ull << 7)) {
+ return 1;
+ } else if (value < (1ull << 14)) {
+ return 2;
+ } else if (value < (1ull << 21)) {
+ return 3;
+ } else if (value < (1ull << 28)) {
+ return 4;
+ } else {
+ return 5;
+ }
+ } else {
+ if (value < (1ull << 42)) {
+ return 6;
+ } else if (value < (1ull << 49)) {
+ return 7;
+ } else if (value < (1ull << 56)) {
+ return 8;
+ } else if (value < (1ull << 63)) {
+ return 9;
+ } else {
+ return 10;
+ }
+ }
+}
+
+} // namespace io
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
new file mode 100644
index 00000000..91e5c56a
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream.h
@@ -0,0 +1,592 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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_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 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 <string>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+
+namespace protobuf {
+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.
+class LIBPROTOBUF_EXPORT CodedInputStream {
+ public:
+ // Create a CodedInputStream that reads from the given ZeroCopyInputStream.
+ explicit CodedInputStream(ZeroCopyInputStream* input);
+
+ // 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();
+
+
+ // Skips a number of bytes. Returns false if an underlying read error
+ // occurs.
+ bool Skip(int count);
+
+ // Read raw bytes, copying them into the given buffer.
+ bool ReadRaw(void* buffer, int size);
+
+ // Like ReadRaw, but reads into a string.
+ //
+ // Implementation Note: ReadString() grows the string gradually as it
+ // reads in the data, rather than allocating the entire requested size
+ // upfront. This prevents denial-of-service attacks in which a client
+ // could claim that a string is going to be MAX_INT bytes long in order to
+ // crash the server because it can't allocate this much space at once.
+ bool ReadString(string* buffer, int size);
+
+
+ // Read a 32-bit little-endian integer.
+ bool ReadLittleEndian32(uint32* value);
+ // Read a 64-bit little-endian integer.
+ bool ReadLittleEndian64(uint64* 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, but may be more efficient.
+ bool ReadVarint32(uint32* value);
+ // Read an unsigned integer with Varint encoding.
+ bool ReadVarint64(uint64* value);
+
+ // Read a tag. This calls ReadVarint32() and returns the result, or returns
+ // zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates
+ // the last tag value, which can be checked with LastTagWas().
+ // Always inline because this is only called in once place per parse loop
+ // but it is called for every iteration of said loop, so it should be fast.
+ // GCC doesn't want to inline this by default.
+ uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
+ // 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.
+ bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
+ // 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() returned the given value, returns true.
+ // Otherwise, returns false;
+ //
+ // 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 expected);
+
+ // 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();
+
+ // 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();
+
+ // Total Bytes Limit -----------------------------------------------
+ // To prevent malicious users from sending excessively large messages
+ // and causing integer overflows or 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 integer overflows in the
+ // protocol buffers implementation, as well as 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 theoretical shortest message that could
+ // cause integer overflows is 512MB. The default limit is 64MB. Apps
+ // should set shorter limits if possible. If warning_threshold is not -1,
+ // a warning will be printed to stderr after warning_threshold bytes are
+ // read. An error will always be printed to stderr if the limit is
+ // reached.
+ //
+ // This is unrelated to PushLimit()/PopLimit().
+ //
+ // Hint: If you are reading this because your program is printing a
+ // warning about dangerously large protocol messages, you may be
+ // confused about what to do next. The best option is to change your
+ // design such that excessively large messages are not necessary.
+ // For example, try to design file formats to consist of many small
+ // messages rather than a single large one. If this is infeasible,
+ // you will need to increase the limit. Chances are, though, that
+ // your code never constructs a CodedInputStream on which the limit
+ // can be set. You probably parse messages by calling things like
+ // Message::ParseFromString(). In this case, you will need to change
+ // your code to instead construct some sort of ZeroCopyInputStream
+ // (e.g. an ArrayInputStream), construct a CodedInputStream around
+ // that, then call Message::ParseFromCodedStream() instead. Then
+ // you can adjust the limit. Yes, it's more work, but you're doing
+ // something unusual.
+ void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold);
+
+ // 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 64.
+ void SetRecursionLimit(int 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.
+ void DecrementRecursionDepth();
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream);
+
+ ZeroCopyInputStream* input_;
+ const uint8* buffer_;
+ int buffer_size_; // size of current buffer
+ 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 last_tag_; // result of last ReadTag().
+
+ // This is set true by ReadVarint32Fallback() 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_;
+ int total_bytes_warning_threshold_;
+
+ // Current recursion depth, controlled by IncrementRecursionDepth() and
+ // DecrementRecursionDepth().
+ int recursion_depth_;
+ // Recursion depth limit, set by SetRecursionLimit().
+ int recursion_limit_;
+
+ // Advance the buffer by a given number of bytes.
+ void Advance(int amount);
+
+ // 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(buffer_size_).
+ bool Refresh();
+
+ bool ReadVarint32Fallback(uint32* value);
+};
+
+// 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.
+class LIBPROTOBUF_EXPORT CodedOutputStream {
+ public:
+ // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
+ explicit CodedOutputStream(ZeroCopyOutputStream* output);
+
+ // Destroy the CodedOutputStream and position the underlying
+ // ZeroCopyOutputStream immediately after the last byte written.
+ ~CodedOutputStream();
+
+ // Write raw bytes, copying them from the given buffer.
+ bool WriteRaw(const void* buffer, int size);
+
+ // Equivalent to WriteRaw(str.data(), str.size()).
+ bool WriteString(const string& str);
+
+
+ // Write a 32-bit little-endian integer.
+ bool WriteLittleEndian32(uint32 value);
+ // Write a 64-bit little-endian integer.
+ bool WriteLittleEndian64(uint64 value);
+
+ // Write an unsigned integer with Varint encoding. Writing a 32-bit value
+ // is equivalent to casting it to uint64 and writing it as a 64-bit value,
+ // but may be more efficient.
+ bool WriteVarint32(uint32 value);
+ // Write an unsigned integer with Varint encoding.
+ bool WriteVarint64(uint64 value);
+
+ // Equivalent to WriteVarint32() except when the value is negative,
+ // in which case it must be sign-extended to a full 10 bytes.
+ bool WriteVarint32SignExtended(int32 value);
+
+ // 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 aformentioned optimization can't work,
+ // but GCC by default doesn't want to inline this.
+ bool WriteTag(uint32 value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
+ // Returns the number of bytes needed to encode the given value as a varint.
+ static int VarintSize32(uint32 value);
+ // Returns the number of bytes needed to encode the given value as a varint.
+ static int VarintSize64(uint64 value);
+
+ // If negative, 10 bytes. Otheriwse, same as VarintSize32().
+ static int VarintSize32SignExtended(int32 value);
+
+ // Returns the total number of bytes written since this object was created.
+ inline int ByteCount() const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
+
+ ZeroCopyOutputStream* output_;
+ uint8* buffer_;
+ int buffer_size_;
+ int total_bytes_; // Sum of sizes of all buffers seen so far.
+
+ // Advance the buffer by a given number of bytes.
+ void Advance(int amount);
+
+ // Called when the buffer runs out to request more data. Implies an
+ // Advance(buffer_size_).
+ bool Refresh();
+
+ bool WriteVarint32Fallback(uint32 value);
+ static int VarintSize32Fallback(uint32 value);
+};
+
+// inline methods ====================================================
+// The vast majority of varints are only one byte. These inline
+// methods optimize for that case.
+
+inline bool CodedInputStream::ReadVarint32(uint32* value) {
+ if (buffer_size_ != 0 && *buffer_ < 0x80) {
+ *value = *buffer_;
+ Advance(1);
+ return true;
+ } else {
+ return ReadVarint32Fallback(value);
+ }
+}
+
+inline uint32 CodedInputStream::ReadTag() {
+ if (buffer_size_ != 0 && buffer_[0] < 0x80) {
+ last_tag_ = buffer_[0];
+ Advance(1);
+ return last_tag_;
+ } else if (buffer_size_ >= 2 && buffer_[1] < 0x80) {
+ last_tag_ = (buffer_[0] & 0x7f) + (buffer_[1] << 7);
+ Advance(2);
+ return last_tag_;
+ } else if (ReadVarint32Fallback(&last_tag_)) {
+ return last_tag_;
+ } else {
+ last_tag_ = 0;
+ return 0;
+ }
+}
+
+inline bool CodedInputStream::LastTagWas(uint32 expected) {
+ return last_tag_ == expected;
+}
+
+inline bool CodedInputStream::ConsumedEntireMessage() {
+ return legitimate_message_end_;
+}
+
+inline bool CodedInputStream::ExpectTag(uint32 expected) {
+ if (expected < (1 << 7)) {
+ if (buffer_size_ != 0 && buffer_[0] == expected) {
+ Advance(1);
+ return true;
+ } else {
+ return false;
+ }
+ } else if (expected < (1 << 14)) {
+ if (buffer_size_ >= 2 &&
+ buffer_[0] == static_cast<uint8>(expected | 0x80) &&
+ buffer_[1] == static_cast<uint8>(expected >> 7)) {
+ Advance(2);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ // Don't bother optimizing for larger values.
+ return false;
+ }
+}
+
+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_size_ == 0 && buffer_size_after_limit_ != 0) {
+ last_tag_ = 0; // Pretend we called ReadTag()...
+ legitimate_message_end_ = true; // ... and it hit EOF.
+ return true;
+ } else {
+ return false;
+ }
+}
+
+inline bool CodedOutputStream::WriteVarint32(uint32 value) {
+ if (value < 0x80 && buffer_size_ > 0) {
+ *buffer_ = value;
+ Advance(1);
+ return true;
+ } else {
+ return WriteVarint32Fallback(value);
+ }
+}
+
+inline bool CodedOutputStream::WriteVarint32SignExtended(int32 value) {
+ if (value < 0) {
+ return WriteVarint64(static_cast<uint64>(value));
+ } else {
+ return WriteVarint32(static_cast<uint32>(value));
+ }
+}
+
+inline bool CodedOutputStream::WriteTag(uint32 value) {
+ if (value < (1 << 7)) {
+ if (buffer_size_ != 0) {
+ buffer_[0] = value;
+ Advance(1);
+ return true;
+ }
+ } else if (value < (1 << 14)) {
+ if (buffer_size_ >= 2) {
+ buffer_[0] = static_cast<uint8>(value | 0x80);
+ buffer_[1] = static_cast<uint8>(value >> 7);
+ Advance(2);
+ return true;
+ }
+ }
+ return WriteVarint32Fallback(value);
+}
+
+inline int CodedOutputStream::VarintSize32(uint32 value) {
+ if (value < (1 << 7)) {
+ return 1;
+ } else {
+ return VarintSize32Fallback(value);
+ }
+}
+
+inline int CodedOutputStream::VarintSize32SignExtended(int32 value) {
+ if (value < 0) {
+ return 10; // TODO(kenton): Make this a symbolic constant.
+ } else {
+ return VarintSize32(static_cast<uint32>(value));
+ }
+}
+
+inline bool CodedOutputStream::WriteString(const string& str) {
+ return WriteRaw(str.data(), str.size());
+}
+
+inline int CodedOutputStream::ByteCount() const {
+ return total_bytes_ - buffer_size_;
+}
+
+inline void CodedInputStream::Advance(int amount) {
+ buffer_ += amount;
+ buffer_size_ -= amount;
+}
+
+inline void CodedOutputStream::Advance(int amount) {
+ buffer_ += amount;
+ buffer_size_ -= amount;
+}
+
+inline void CodedInputStream::SetRecursionLimit(int limit) {
+ recursion_limit_ = limit;
+}
+
+inline bool CodedInputStream::IncrementRecursionDepth() {
+ ++recursion_depth_;
+ return recursion_depth_ <= recursion_limit_;
+}
+
+inline void CodedInputStream::DecrementRecursionDepth() {
+ if (recursion_depth_ > 0) --recursion_depth_;
+}
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..c1a88349
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -0,0 +1,929 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+
+#include <limits.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+// This declares an unsigned long long integer literal in a portable way.
+// (The original macro is way too big and ruins my formatting.)
+#undef ULL
+#define ULL(x) GOOGLE_ULONGLONG(x)
+
+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<<.
+
+#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)
+
+// ===================================================================
+
+class CodedStreamTest : public testing::Test {
+ protected:
+ static const int kBufferSize = 1024 * 64;
+ static uint8 buffer_[kBufferSize];
+};
+
+uint8 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 bytes[10]; // Encoded bytes.
+ int size; // Encoded size, in bytes.
+ uint64 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) |
+ (ULL(0x0b) << 28)},
+
+ // 64-bit
+ {{0xbe, 0xf7, 0x92, 0x84, 0x1b}, 5, // 7256456126
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (ULL(0x1b) << 28)},
+ {{0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, 8, // 41256202580718336
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+ (ULL(0x43) << 28) | (ULL(0x49) << 35) | (ULL(0x24) << 42) |
+ (ULL(0x49) << 49)},
+ // 11964378330978735131
+ {{0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, 10,
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+ (ULL(0x3b) << 28) | (ULL(0x56) << 35) | (ULL(0x00) << 42) |
+ (ULL(0x05) << 49) | (ULL(0x26) << 56) | (ULL(0x01) << 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 value;
+ EXPECT_TRUE(coded_input.ReadVarint32(&value));
+ EXPECT_EQ(static_cast<uint32>(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 expected_value = static_cast<uint32>(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());
+}
+
+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 dummy;
+ coded_input.ReadRaw(&dummy, 1);
+ EXPECT_EQ((uint)'\0', (uint)dummy);
+
+ uint32 expected_value = static_cast<uint32>(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_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 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 > ULL(0x00000000FFFFFFFF)) {
+ // Skip this test for the 64-bit values.
+ return;
+ }
+
+ ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedOutputStream coded_output(&output);
+
+ EXPECT_TRUE(coded_output.WriteVarint32(
+ static_cast<uint32>(kVarintCases_case.value)));
+
+ 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);
+
+ EXPECT_TRUE(coded_output.WriteVarint64(kVarintCases_case.value));
+
+ 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 kSignExtendedVarintCases[] = {
+ 0, 1, -1, 1237894, -37895138
+};
+
+TEST_2D(CodedStreamTest, WriteVarint32SignExtended,
+ kSignExtendedVarintCases, kBlockSizes) {
+ ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedOutputStream coded_output(&output);
+
+ EXPECT_TRUE(coded_output.WriteVarint32SignExtended(
+ kSignExtendedVarintCases_case));
+
+ 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 value;
+ EXPECT_TRUE(coded_input.ReadVarint64(&value));
+
+ EXPECT_EQ(kSignExtendedVarintCases_case, static_cast<int64>(value));
+ }
+
+ EXPECT_EQ(output.ByteCount(), input.ByteCount());
+}
+
+#endif
+
+
+// -------------------------------------------------------------------
+// Varint failure test.
+
+struct VarintErrorCase {
+ uint8 bytes[12];
+ int 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_, kVarintErrorCases_case.size,
+ kBlockSizes_case);
+ CodedInputStream coded_input(&input);
+
+ uint32 value;
+ EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint32(&value));
+}
+
+TEST_2D(CodedStreamTest, ReadVarint64Error, kVarintErrorCases, kBlockSizes) {
+ memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
+ ArrayInputStream input(buffer_, kVarintErrorCases_case.size,
+ kBlockSizes_case);
+ CodedInputStream coded_input(&input);
+
+ uint64 value;
+ EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint64(&value));
+}
+
+// -------------------------------------------------------------------
+// VarintSize
+
+struct VarintSizeCase {
+ uint64 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},
+ {ULL(41256202580718336), 8},
+ {ULL(11964378330978735131), 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>(kVarintSizeCases_case.value)));
+}
+
+TEST_1D(CodedStreamTest, VarintSize64, kVarintSizeCases) {
+ EXPECT_EQ(kVarintSizeCases_case.size,
+ CodedOutputStream::VarintSize64(kVarintSizeCases_case.value));
+}
+
+// -------------------------------------------------------------------
+// Fixed-size int tests
+
+struct Fixed32Case {
+ uint8 bytes[sizeof(uint32)]; // Encoded bytes.
+ uint32 value; // Parsed value.
+};
+
+struct Fixed64Case {
+ uint8 bytes[sizeof(uint64)]; // Encoded bytes.
+ uint64 value; // Parsed value.
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
+ return os << "0x" << hex << c.value << dec;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
+ return os << "0x" << hex << c.value << dec;
+}
+
+Fixed32Case kFixed32Cases[] = {
+ {{0xef, 0xcd, 0xab, 0x90}, 0x90abcdefu},
+ {{0x12, 0x34, 0x56, 0x78}, 0x78563412u},
+};
+
+Fixed64Case kFixed64Cases[] = {
+ {{0xef, 0xcd, 0xab, 0x90, 0x12, 0x34, 0x56, 0x78}, ULL(0x7856341290abcdef)},
+ {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, ULL(0x8877665544332211)},
+};
+
+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 value;
+ EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+ EXPECT_EQ(kFixed32Cases_case.value, value);
+ }
+
+ EXPECT_EQ(sizeof(uint32), 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 value;
+ EXPECT_TRUE(coded_input.ReadLittleEndian64(&value));
+ EXPECT_EQ(kFixed64Cases_case.value, value);
+ }
+
+ EXPECT_EQ(sizeof(uint64), input.ByteCount());
+}
+
+TEST_2D(CodedStreamTest, WriteLittleEndian32, kFixed32Cases, kBlockSizes) {
+ ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedOutputStream coded_output(&output);
+
+ EXPECT_TRUE(coded_output.WriteLittleEndian32(kFixed32Cases_case.value));
+
+ EXPECT_EQ(sizeof(uint32), coded_output.ByteCount());
+ }
+
+ EXPECT_EQ(sizeof(uint32), output.ByteCount());
+ EXPECT_EQ(0, memcmp(buffer_, kFixed32Cases_case.bytes, sizeof(uint32)));
+}
+
+TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) {
+ ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedOutputStream coded_output(&output);
+
+ EXPECT_TRUE(coded_output.WriteLittleEndian64(kFixed64Cases_case.value));
+
+ EXPECT_EQ(sizeof(uint64), coded_output.ByteCount());
+ }
+
+ EXPECT_EQ(sizeof(uint64), output.ByteCount());
+ EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64)));
+}
+
+// -------------------------------------------------------------------
+// Raw reads and writes
+
+const char kRawBytes[] = "Some bytes which will be writted 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);
+
+ EXPECT_TRUE(coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes)));
+
+ 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);
+
+ 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);
+
+ string str;
+ // Try to read a gigabyte.
+ EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+ }
+}
+
+
+// -------------------------------------------------------------------
+// Skip
+
+const char kSkipTestBytes[] =
+ "<Before skipping><To be skipped><After skipping>";
+const char kSkipOutputTestBytes[] =
+ "-----------------<To be skipped>----------------";
+
+TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) {
+ memcpy(buffer_, kSkipTestBytes, sizeof(kSkipTestBytes));
+ ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+ {
+ CodedInputStream coded_input(&input);
+
+ 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());
+}
+
+// -------------------------------------------------------------------
+// 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 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 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 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 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, -1);
+
+ string str;
+ EXPECT_TRUE(coded_input.ReadString(&str, 16));
+
+ vector<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, -1);
+ EXPECT_TRUE(coded_input.ReadString(&str, 16));
+}
+
+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, -1);
+ CodedInputStream::Limit limit = coded_input.PushLimit(16);
+
+ // Read 16 bytes.
+ 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.ReadTag());
+ 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.ReadTag());
+ 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) {}
+ ~ReallyBigInputStream() {}
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size) {
+ // 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) {
+ backup_amount_ = count;
+ }
+
+ bool Skip(int count) { GOOGLE_LOG(FATAL) << "Not implemented."; return false; }
+ int64 ByteCount() const { GOOGLE_LOG(FATAL) << "Not implemented."; return 0; }
+
+ int backup_amount_;
+
+ private:
+ char buffer_[1024];
+ int64 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;
+
+ vector<string> errors;
+
+ {
+ ScopedMemoryLog error_log;
+ CodedInputStream coded_input(&input);
+ 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
diff --git a/src/google/protobuf/io/package_info.h b/src/google/protobuf/io/package_info.h
new file mode 100644
index 00000000..8272d51d
--- /dev/null
+++ b/src/google/protobuf/io/package_info.h
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 00000000..7b3e3de4
--- /dev/null
+++ b/src/google/protobuf/io/printer.cc
@@ -0,0 +1,165 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.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),
+ at_start_of_line_(true),
+ failed_(false) {
+}
+
+Printer::~Printer() {
+ // Only BackUp() if we're sure we've successfully called Next() at least once.
+ if (buffer_size_ > 0) {
+ output_->BackUp(buffer_size_);
+ }
+}
+
+void Printer::Print(const map<string, string>& variables, const char* text) {
+ int size = strlen(text);
+ int pos = 0; // The number of bytes we've written so far.
+
+ 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'.
+ 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;
+
+ } else if (text[i] == variable_delimiter_) {
+ // Saw the start of a variable name.
+
+ // Write what we have so far.
+ Write(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;
+
+ string varname(text + pos, endpos - pos);
+ if (varname.empty()) {
+ // Two delimiters in a row reduce to a literal delimiter character.
+ Write(&variable_delimiter_, 1);
+ } else {
+ // Replace with the variable's value.
+ map<string, string>::const_iterator iter = variables.find(varname);
+ if (iter == variables.end()) {
+ GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
+ } else {
+ Write(iter->second.data(), iter->second.size());
+ }
+ }
+
+ // Advance past this variable.
+ i = endpos;
+ pos = endpos + 1;
+ }
+ }
+
+ // Write the rest.
+ Write(text + pos, size - pos);
+}
+
+void Printer::Print(const char* text) {
+ static map<string, string> empty;
+ Print(empty, text);
+}
+
+void Printer::Print(const char* text,
+ const char* variable, const string& value) {
+ map<string, string> vars;
+ vars[variable] = value;
+ Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+ const char* variable1, const string& value1,
+ const char* variable2, const string& value2) {
+ map<string, string> vars;
+ vars[variable1] = value1;
+ vars[variable2] = value2;
+ Print(vars, text);
+}
+
+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::Write(const char* data, int size) {
+ if (failed_) return;
+ if (size == 0) return;
+
+ if (at_start_of_line_) {
+ // Insert an indent.
+ at_start_of_line_ = false;
+ Write(indent_.data(), indent_.size());
+ if (failed_) return;
+ }
+
+ while (size > buffer_size_) {
+ // Data exceeds space in the buffer. Copy what we can and request a
+ // new buffer.
+ memcpy(buffer_, data, 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;
+}
+
+} // 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 00000000..ee8f46c8
--- /dev/null
+++ b/src/google/protobuf/io/printer.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <map>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyOutputStream; // zero_copy_stream.h
+
+// 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. This helps greatly in debugging code
+// which uses it. This class is not intended to be used by production servers.
+class LIBPROTOBUF_EXPORT Printer {
+ public:
+ // Create a printer that writes text to the given output stream. Use the
+ // given character as the delimiter for variables.
+ Printer(ZeroCopyOutputStream* output, char variable_delimiter);
+ ~Printer();
+
+ // 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 map<string, string>& variables, const char* text);
+
+ // Like the first Print(), except the substitutions are given as parameters.
+ void Print(const char* text);
+ // Like the first Print(), except the substitutions are given as parameters.
+ void Print(const char* text, const char* variable, const string& value);
+ // Like the first Print(), except the substitutions are given as parameters.
+ void Print(const char* text, const char* variable1, const string& value1,
+ const char* variable2, const string& value2);
+ // TODO(kenton): Overloaded versions with more variables? Two seems
+ // to be enough.
+
+ // 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();
+
+ // 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:
+ // Write some text to the output buffer.
+ void Write(const char* data, int size);
+
+ const char variable_delimiter_;
+
+ ZeroCopyOutputStream* const output_;
+ char* buffer_;
+ int buffer_size_;
+
+ string indent_;
+ bool at_start_of_line_;
+ bool failed_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
+};
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..652728bc
--- /dev/null
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -0,0 +1,210 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+// 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(buffer,
+ "Hello World! This is the same line.\n"
+ "But this is a new one.\n"
+ "And this is another one.");
+ }
+}
+
+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, '$');
+ map<string, string> vars;
+
+ vars["foo"] = "World";
+ vars["bar"] = "$foo$";
+ vars["abcdefg"] = "1234";
+
+ printer.Print(vars, "Hello $foo$!\nbar = $bar$\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(buffer,
+ "Hello World!\n"
+ "bar = $foo$\n"
+ "1234\n"
+ "A literal dollar sign: $\n"
+ "Now foo = blah.");
+ }
+}
+
+TEST(Printer, InlineVariableSubstitution) {
+ char buffer[8192];
+
+ ArrayOutputStream output(buffer, sizeof(buffer));
+
+ {
+ Printer printer(&output, '$');
+ printer.Print("Hello $foo$!\n", "foo", "World");
+ printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
+ EXPECT_FALSE(printer.failed());
+ }
+
+ buffer[output.ByteCount()] = '\0';
+
+ EXPECT_STREQ(buffer,
+ "Hello World!\n"
+ "one two\n");
+}
+
+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, '$');
+ map<string, 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.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(buffer,
+ "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"
+ " 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.");
+ }
+}
+
+// Death tests do not work on Windows as of yet.
+#ifdef GTEST_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");
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(Printer, WriteFailure) {
+ 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", string(buffer, sizeof(buffer)));
+}
+
+} // namespace
+} // namespace io
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
new file mode 100644
index 00000000..3864fcfb
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -0,0 +1,679 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+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');
+
+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.
+inline int DigitValue(char digit) {
+ if ('0' <= digit && digit <= '9') return digit - '0';
+ if ('a' <= digit && digit <= 'z') return digit - 'a' + 10;
+ if ('A' <= digit && digit <= 'Z') return digit - 'A' + 10;
+ return -1;
+}
+
+// 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),
+ token_start_(-1),
+ allow_f_after_float_(false),
+ comment_style_(CPP_COMMENT_STYLE) {
+
+ current_.line = 0;
+ current_.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_);
+ }
+}
+
+// -------------------------------------------------------------------
+// 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 (token_start_ >= 0 && token_start_ < buffer_size_) {
+ current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_);
+ token_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::StartToken() {
+ token_start_ = buffer_pos_;
+ current_.type = TYPE_START; // Just for the sake of initializing it.
+ current_.text.clear();
+ current_.line = line_;
+ current_.column = column_;
+}
+
+inline void Tokenizer::EndToken() {
+ // 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_ != token_start_) {
+ current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_);
+ }
+ token_start_ = -1;
+}
+
+// -------------------------------------------------------------------
+// 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':
+ case '\n': {
+ AddError("String literals cannot cross line boundaries.");
+ return;
+ }
+
+ 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') || 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 {
+ 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>()) {
+ 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() {
+ while (current_char_ != '\0' && current_char_ != '\n') {
+ NextChar();
+ }
+ TryConsume('\n');
+}
+
+void Tokenizer::ConsumeBlockComment() {
+ int start_line = line_;
+ int start_column = column_ - 2;
+
+ while (true) {
+ while (current_char_ != '\0' &&
+ current_char_ != '*' &&
+ current_char_ != '/') {
+ NextChar();
+ }
+
+ if (TryConsume('*') && TryConsume('/')) {
+ // End of comment.
+ 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.");
+ break;
+ }
+ }
+}
+
+// -------------------------------------------------------------------
+
+bool Tokenizer::Next() {
+ TokenType last_token_type = current_.type;
+
+ // Did we skip any characters after the last token?
+ bool skipped_stuff = false;
+
+ while (!read_error_) {
+ if (TryConsumeOne<Whitespace>()) {
+ ConsumeZeroOrMore<Whitespace>();
+
+ } else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
+ // Starting a comment?
+ if (TryConsume('/')) {
+ ConsumeLineComment();
+ } else if (TryConsume('*')) {
+ ConsumeBlockComment();
+ } else {
+ // Oops, it was just a slash. Return it.
+ current_.type = TYPE_SYMBOL;
+ current_.text = "/";
+ current_.line = line_;
+ current_.column = column_ - 1;
+ return true;
+ }
+
+ } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
+ ConsumeLineComment();
+
+ } else 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 (last_token_type == TYPE_IDENTIFIER && !skipped_stuff) {
+ // 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 {
+ NextChar();
+ current_.type = TYPE_SYMBOL;
+ }
+
+ EndToken();
+ return true;
+ }
+
+ skipped_stuff = true;
+ }
+
+ // EOF
+ current_.type = TYPE_END;
+ current_.text.clear();
+ current_.line = line_;
+ current_.column = column_;
+ return false;
+}
+
+// -------------------------------------------------------------------
+// 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 string& text, uint64 max_value,
+ uint64* output) {
+ // Sadly, we can't just use strtoul() since it is only 32-bit and strtoull()
+ // is non-standard. I hate the C standard library. :(
+
+// return strtoull(text.c_str(), NULL, 0);
+
+ const char* ptr = text.c_str();
+ int base = 10;
+ if (ptr[0] == '0') {
+ if (ptr[1] == 'x') {
+ // This is hex.
+ base = 16;
+ ptr += 2;
+ } else {
+ // This is octal.
+ base = 8;
+ }
+ }
+
+ uint64 result = 0;
+ for (; *ptr != '\0'; ptr++) {
+ int digit = DigitValue(*ptr);
+ GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base)
+ << " Tokenizer::ParseInteger() passed text that could not have been"
+ " tokenized as an integer: " << CEscape(text);
+ if (digit > max_value || result > (max_value - digit) / base) {
+ // Overflow.
+ return false;
+ }
+ result = result * base + digit;
+ }
+
+ *output = result;
+ return true;
+}
+
+double Tokenizer::ParseFloat(const 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, end - start != text.size() || *start == '-')
+ << " Tokenizer::ParseFloat() passed text that could not have been"
+ " tokenized as a float: " << CEscape(text);
+ return result;
+}
+
+void Tokenizer::ParseString(const string& text, string* output) {
+ output->clear();
+
+ // Reminder: text[0] is always the quote character. (If text is
+ // empty, it's invalid, so we'll just return.)
+ if (text.empty()) {
+ GOOGLE_LOG(DFATAL)
+ << " ParseString::ParseString() passed text that could not have been"
+ " tokenized as a string: " << CEscape(text);
+ return;
+ }
+
+ output->reserve(text.size());
+
+ // 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 {
+ // Some other escape code.
+ output->push_back(TranslateEscape(*ptr));
+ }
+
+ } else if (*ptr == text[0]) {
+ // Ignore quote matching the starting quote.
+ } else {
+ output->push_back(*ptr);
+ }
+ }
+
+ return;
+}
+
+} // namespace io
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
new file mode 100644
index 00000000..841564ce
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer.h
@@ -0,0 +1,276 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyInputStream; // zero_copy_stream.h
+
+// Defined in this file.
+class ErrorCollector;
+class Tokenizer;
+
+// Abstract interface for an object which collects the errors that occur
+// during parsing. A typical implementation might simply print the errors
+// to stdout.
+class LIBPROTOBUF_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, int column, const string& message) = 0;
+
+ 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 LIBPROTOBUF_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.
+ };
+
+ // Structure representing a token read from the token stream.
+ struct Token {
+ TokenType type;
+ 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;
+ int 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();
+
+ // Advance to the next token. Returns false if the end of the input is
+ // reached.
+ bool Next();
+
+ // 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 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 string& text, 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 string& text, uint64 max_value,
+ uint64* 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; }
+
+ // -----------------------------------------------------------------
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
+
+ Token current_; // Returned by current().
+
+ 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_;
+ int column_;
+
+ // Position in buffer_ where StartToken() was called. If the token
+ // started in the previous buffer, this is zero, and current_.text already
+ // contains the part of the token from the previous buffer. If not
+ // currently parsing a token, this is -1.
+ int token_start_;
+
+ // Options.
+ bool allow_f_after_float_;
+ CommentStyle comment_style_;
+
+ // 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.
+ 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();
+
+ // 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 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 characted 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();
+ // Consume until "*/".
+ void ConsumeBlockComment();
+
+ // -----------------------------------------------------------------
+ // These helper methods make the parsing code more readable. The
+ // "character classes" refered 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_;
+}
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..e2cede7e
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -0,0 +1,706 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+#include <math.h>
+#include <limits.h>
+
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.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 fetaures 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) {
+ // 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) { return array_stream_.BackUp(count); }
+ bool Skip(int count) { return array_stream_.Skip(count); }
+ int64 ByteCount() const { 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() {}
+
+ string text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(int line, int column, const 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 ParseInteger(const string& text) {
+ uint64 result;
+ EXPECT_TRUE(Tokenizer::ParseInteger(text, kuint64max, &result));
+ 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 {
+ string input;
+ Tokenizer::TokenType type;
+};
+
+inline ostream& operator<<(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);
+
+ // 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);
+
+ // 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);
+
+ // 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());
+}
+
+#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 {
+ string input;
+ Tokenizer::Token output[10]; // The compiler wants a constant array
+ // size for initialization to work. There
+ // is no reason this can't be increased if
+ // needed.
+};
+
+inline ostream& operator<<(ostream& out,
+ const MultiTokenCase& test_case) {
+ return out << CEscape(test_case.input);
+}
+
+MultiTokenCase kMultiTokenCases[] = {
+ // Test empty input.
+ { "", {
+ { Tokenizer::TYPE_END , "" , 0, 0 },
+ }},
+
+ // Test all token types at the same time.
+ { "foo 1 1.2 + 'bar'", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo" , 0, 0 },
+ { Tokenizer::TYPE_INTEGER , "1" , 0, 4 },
+ { Tokenizer::TYPE_FLOAT , "1.2" , 0, 6 },
+ { Tokenizer::TYPE_SYMBOL , "+" , 0, 10 },
+ { Tokenizer::TYPE_STRING , "'bar'", 0, 12 },
+ { Tokenizer::TYPE_END , "" , 0, 17 },
+ }},
+
+ // Test that consecutive symbols are parsed as separate tokens.
+ { "!@+%", {
+ { Tokenizer::TYPE_SYMBOL , "!" , 0, 0 },
+ { Tokenizer::TYPE_SYMBOL , "@" , 0, 1 },
+ { Tokenizer::TYPE_SYMBOL , "+" , 0, 2 },
+ { Tokenizer::TYPE_SYMBOL , "%" , 0, 3 },
+ { Tokenizer::TYPE_END , "" , 0, 4 },
+ }},
+
+ // Test that newlines affect line numbers correctly.
+ { "foo bar\nrab oof", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
+ { Tokenizer::TYPE_IDENTIFIER, "bar", 0, 4 },
+ { Tokenizer::TYPE_IDENTIFIER, "rab", 1, 0 },
+ { Tokenizer::TYPE_IDENTIFIER, "oof", 1, 4 },
+ { Tokenizer::TYPE_END , "" , 1, 7 },
+ }},
+
+ // Test that tabs affect column numbers correctly.
+ { "foo\tbar \tbaz", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
+ { Tokenizer::TYPE_IDENTIFIER, "bar", 0, 8 },
+ { Tokenizer::TYPE_IDENTIFIER, "baz", 0, 16 },
+ { Tokenizer::TYPE_END , "" , 0, 19 },
+ }},
+
+ // Test that line comments are ignored.
+ { "foo // This is a comment\n"
+ "bar // This is another comment", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
+ { Tokenizer::TYPE_IDENTIFIER, "bar", 1, 0 },
+ { Tokenizer::TYPE_END , "" , 1, 30 },
+ }},
+
+ // Test that block comments are ignored.
+ { "foo /* This is a block comment */ bar", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
+ { Tokenizer::TYPE_IDENTIFIER, "bar", 0, 34 },
+ { Tokenizer::TYPE_END , "" , 0, 37 },
+ }},
+
+ // Test that sh-style comments are not ignored by default.
+ { "foo # bar\n"
+ "baz", {
+ { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
+ { Tokenizer::TYPE_SYMBOL , "#" , 0, 4 },
+ { Tokenizer::TYPE_IDENTIFIER, "bar", 0, 6 },
+ { Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0 },
+ { Tokenizer::TYPE_END , "" , 1, 3 },
+ }},
+};
+
+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);
+
+ // 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);
+
+ // 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 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);
+
+ } 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
+
+// -------------------------------------------------------------------
+
+// Test parse helpers. It's not really worth setting up a full data-driven
+// test here.
+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"));
+
+ // Test invalid integers that may still be tokenized as integers.
+ EXPECT_EQ(0, ParseInteger("0x"));
+
+#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
+ // Test invalid integers that will never be tokenized as integers.
+ EXPECT_DEBUG_DEATH(ParseInteger("zxy"),
+ "passed text that could not have been tokenized as an integer");
+ EXPECT_DEBUG_DEATH(ParseInteger("1.2"),
+ "passed text that could not have been tokenized as an integer");
+ EXPECT_DEBUG_DEATH(ParseInteger("08"),
+ "passed text that could not have been tokenized as an integer");
+ EXPECT_DEBUG_DEATH(ParseInteger("0xg"),
+ "passed text that could not have been tokenized as an integer");
+ EXPECT_DEBUG_DEATH(ParseInteger("-1"),
+ "passed text that could not have been tokenized as an integer");
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Test overflows.
+ uint64 i;
+ 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_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 GTEST_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 // GTEST_HAS_DEATH_TEST
+}
+
+TEST_F(TokenizerTest, ParseString) {
+ 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);
+
+ // Test invalid strings that will never be tokenized as strings.
+#ifdef GTEST_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 // GTEST_HAS_DEATH_TEST
+}
+
+// -------------------------------------------------------------------
+
+// Each case parses some input text, ignoring the tokens produced, and
+// checks that the error output matches what is expected.
+struct ErrorCase {
+ 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 ostream& operator<<(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:3: Expected hex digits for escape sequence.\n" },
+ { "'foo", false,
+ "0:4: String literals cannot cross line boundaries.\n" },
+ { "'bar\nfoo", true,
+ "0:4: String literals cannot cross line boundaries.\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.
+ { string("\0foo", 4), true,
+ "0:0: Invalid control characters encountered in text.\n" },
+ { string("\0\0foo", 5), true,
+ "0:0: Invalid control characters encountered in text.\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(error_collector.text_, kErrorCases_case.errors);
+
+ // 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) {
+ 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 00000000..80559c4a
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream.cc
@@ -0,0 +1,34 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+ZeroCopyInputStream::~ZeroCopyInputStream() {}
+ZeroCopyOutputStream::~ZeroCopyOutputStream() {}
+
+
+} // 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 00000000..bce5f2d3
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream.h
@@ -0,0 +1,224 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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);
+// ZeroCopyInputStream* 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 <string>
+#include <google/protobuf/stubs/common.h>
+
+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 LIBPROTOBUF_EXPORT ZeroCopyInputStream {
+ public:
+ inline 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.
+ //
+ // 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 ByteCount() const = 0;
+
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
+};
+
+// Abstract interface similar to an output stream but designed to minimize
+// copying.
+class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
+ public:
+ inline 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 ByteCount() const = 0;
+
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
+};
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..7ff84460
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -0,0 +1,793 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <iostream>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stl_util-inl.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)
+#endif
+
+namespace {
+
+
+// EINTR sucks.
+int close_no_eintr(int fd) {
+ int result;
+ do {
+ result = close(fd);
+ } while (result < 0 && errno == EINTR);
+ return result;
+}
+
+// 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*>(data)),
+ size_(size),
+ block_size_(block_size > 0 ? block_size : size),
+ position_(0),
+ last_returned_size_(0) {
+}
+
+ArrayInputStream::~ArrayInputStream() {
+}
+
+bool ArrayInputStream::Next(const void** data, int* size) {
+ if (position_ < size_) {
+ last_returned_size_ = 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 ArrayInputStream::ByteCount() const {
+ return position_;
+}
+
+
+// ===================================================================
+
+ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
+ : data_(reinterpret_cast<uint8*>(data)),
+ size_(size),
+ block_size_(block_size > 0 ? block_size : size),
+ position_(0),
+ last_returned_size_(0) {
+}
+
+ArrayOutputStream::~ArrayOutputStream() {
+}
+
+bool ArrayOutputStream::Next(void** data, int* size) {
+ if (position_ < size_) {
+ last_returned_size_ = 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_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.
+}
+
+int64 ArrayOutputStream::ByteCount() const {
+ return position_;
+}
+
+// ===================================================================
+
+StringOutputStream::StringOutputStream(string* target)
+ : target_(target) {
+}
+
+StringOutputStream::~StringOutputStream() {
+}
+
+bool StringOutputStream::Next(void** data, int* size) {
+ int old_size = target_->size();
+
+ // Grow the string.
+ if (old_size < target_->capacity()) {
+ // Resize the string to match its capacity, since we can get away
+ // without a memory allocation this way.
+ target_->resize(target_->capacity());
+ } else {
+ // Size has reached capacity, so double the size. Also make sure
+ // that the new size is at least kMinimumSize.
+ target_->resize(
+ max(old_size * 2,
+ kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
+ }
+
+ *data = string_as_array(target_) + old_size;
+ *size = target_->size() - old_size;
+ return true;
+}
+
+void StringOutputStream::BackUp(int count) {
+ GOOGLE_CHECK_GE(count, 0);
+ GOOGLE_CHECK_LE(count, target_->size());
+ target_->resize(target_->size() - count);
+}
+
+int64 StringOutputStream::ByteCount() const {
+ return target_->size();
+}
+
+// ===================================================================
+
+
+// ===================================================================
+
+CopyingInputStream::~CopyingInputStream() {}
+
+int CopyingInputStream::Skip(int count) {
+ char junk[4096];
+ int skipped = 0;
+ while (skipped < count) {
+ int bytes = Read(junk, min(count, 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 CopyingInputStreamAdaptor::ByteCount() const {
+ return position_ - backup_bytes_;
+}
+
+void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
+ if (buffer_.get() == NULL) {
+ buffer_.reset(new uint8[buffer_size_]);
+ }
+}
+
+void CopyingInputStreamAdaptor::FreeBuffer() {
+ GOOGLE_CHECK_EQ(backup_bytes_, 0);
+ buffer_used_ = 0;
+ buffer_.reset();
+}
+
+// ===================================================================
+
+CopyingOutputStream::~CopyingOutputStream() {}
+
+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) {
+ 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 CopyingOutputStreamAdaptor::ByteCount() const {
+ return position_ + buffer_used_;
+}
+
+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[buffer_size_]);
+ }
+}
+
+void CopyingOutputStreamAdaptor::FreeBuffer() {
+ buffer_used_ = 0;
+ buffer_.reset();
+}
+
+// ===================================================================
+
+FileInputStream::FileInputStream(int file_descriptor, int block_size)
+ : copying_input_(file_descriptor),
+ impl_(&copying_input_, block_size) {
+}
+
+FileInputStream::~FileInputStream() {}
+
+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 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) {
+}
+
+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)
+ : copying_output_(file_descriptor),
+ impl_(&copying_output_, block_size) {
+}
+
+FileOutputStream::~FileOutputStream() {
+ impl_.Flush();
+}
+
+bool FileOutputStream::Close() {
+ bool flush_succeeded = impl_.Flush();
+ return copying_output_.Close() && flush_succeeded;
+}
+
+bool FileOutputStream::Next(void** data, int* size) {
+ return impl_.Next(data, size);
+}
+
+void FileOutputStream::BackUp(int count) {
+ impl_.BackUp(count);
+}
+
+int64 FileOutputStream::ByteCount() const {
+ return impl_.ByteCount();
+}
+
+FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
+ int file_descriptor)
+ : file_(file_descriptor),
+ close_on_delete_(false),
+ is_closed_(false),
+ errno_(0) {
+}
+
+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* buffer_base = reinterpret_cast<const uint8*>(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(istream* input, int block_size)
+ : copying_input_(input),
+ impl_(&copying_input_, block_size) {
+}
+
+IstreamInputStream::~IstreamInputStream() {}
+
+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 IstreamInputStream::ByteCount() const {
+ return impl_.ByteCount();
+}
+
+IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
+ 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(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 OstreamOutputStream::ByteCount() const {
+ return impl_.ByteCount();
+}
+
+OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
+ 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) {
+}
+
+ConcatenatingInputStream::~ConcatenatingInputStream() {
+}
+
+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 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 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 ConcatenatingInputStream::ByteCount() const {
+ if (stream_count_ == 0) {
+ return bytes_retired_;
+ } else {
+ return bytes_retired_ + streams_[0]->ByteCount();
+ }
+}
+
+
+// ===================================================================
+
+LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
+ int64 limit)
+ : input_(input), limit_(limit) {}
+
+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 LimitingInputStream::ByteCount() const {
+ if (limit_ < 0) {
+ return input_->ByteCount() + limit_;
+ } else {
+ return input_->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 00000000..bd73afb7
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -0,0 +1,617 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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. These implementations cover I/O on raw arrays,
+// strings, and file descriptors. 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_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
+
+#include <string>
+#include <iosfwd>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/common.h>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ===================================================================
+
+// A ZeroCopyInputStream backed by an in-memory array of bytes.
+class LIBPROTOBUF_EXPORT ArrayInputStream : 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();
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+
+ private:
+ const uint8* 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 LIBPROTOBUF_EXPORT ArrayOutputStream : 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();
+
+ // implements ZeroCopyOutputStream ---------------------------------
+ bool Next(void** data, int* size);
+ void BackUp(int count);
+ int64 ByteCount() const;
+
+ private:
+ uint8* 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 LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
+ public:
+ // Create a StringOutputStream which appends bytes to the given string.
+ // The string remains property of the caller, but it MUST NOT be accessed
+ // in any way until the stream is destroyed.
+ //
+ // 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(string* target);
+ ~StringOutputStream();
+
+ // implements ZeroCopyOutputStream ---------------------------------
+ bool Next(void** data, int* size);
+ void BackUp(int count);
+ int64 ByteCount() const;
+
+ private:
+ static const int kMinimumSize = 16;
+
+ 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 LIBPROTOBUF_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 LIBPROTOBUF_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();
+
+ // 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);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+ 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 permenant error from the underlying stream.
+ bool failed_;
+
+ // The current position of copying_stream_, relative to the point where
+ // we started reading.
+ int64 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_.
+ scoped_array<uint8> 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 LIBPROTOBUF_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 LIBPROTOBUF_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();
+
+ // 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);
+ void BackUp(int count);
+ int64 ByteCount() const;
+
+ 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 permenant error from the underlying stream.
+ bool failed_;
+
+ // The current position of copying_stream_, relative to the point where
+ // we started writing.
+ int64 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_.
+ scoped_array<uint8> 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 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 LIBPROTOBUF_EXPORT FileInputStream : 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);
+ ~FileInputStream();
+
+ // 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() { return copying_input_.GetErrno(); }
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+ private:
+ class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
+ public:
+ CopyingFileInputStream(int file_descriptor);
+ ~CopyingFileInputStream();
+
+ bool Close();
+ void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+ int GetErrno() { return errno_; }
+
+ // implements CopyingInputStream ---------------------------------
+ int Read(void* buffer, int size);
+ int Skip(int count);
+
+ 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.
+//
+// FileInputStream is preferred over using an ofstream with OstreamOutputStream.
+// 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 LIBPROTOBUF_EXPORT FileOutputStream : 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 FileOutputStream(int file_descriptor, int block_size = -1);
+ ~FileOutputStream();
+
+ // 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() { return copying_output_.GetErrno(); }
+
+ // implements ZeroCopyOutputStream ---------------------------------
+ bool Next(void** data, int* size);
+ void BackUp(int count);
+ int64 ByteCount() const;
+
+ private:
+ class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
+ public:
+ CopyingFileOutputStream(int file_descriptor);
+ ~CopyingFileOutputStream();
+
+ bool Close();
+ void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+ int GetErrno() { return errno_; }
+
+ // implements CopyingOutputStream --------------------------------
+ bool Write(const void* buffer, int size);
+
+ 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_;
+ CopyingOutputStreamAdaptor impl_;
+
+ 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 LIBPROTOBUF_EXPORT IstreamInputStream : 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(istream* stream, int block_size = -1);
+ ~IstreamInputStream();
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+ private:
+ class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
+ public:
+ CopyingIstreamInputStream(istream* input);
+ ~CopyingIstreamInputStream();
+
+ // implements CopyingInputStream ---------------------------------
+ int Read(void* buffer, int size);
+ // (We use the default implementation of Skip().)
+
+ private:
+ // The stream.
+ 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 LIBPROTOBUF_EXPORT OstreamOutputStream : 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(ostream* stream, int block_size = -1);
+ ~OstreamOutputStream();
+
+ // implements ZeroCopyOutputStream ---------------------------------
+ bool Next(void** data, int* size);
+ void BackUp(int count);
+ int64 ByteCount() const;
+
+ private:
+ class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream {
+ public:
+ CopyingOstreamOutputStream(ostream* output);
+ ~CopyingOstreamOutputStream();
+
+ // implements CopyingOutputStream --------------------------------
+ bool Write(const void* buffer, int size);
+
+ private:
+ // The stream.
+ 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 LIBPROTOBUF_EXPORT ConcatenatingInputStream : 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();
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+
+ private:
+ // As streams are retired, streams_ is incremented and count_ is
+ // decremented.
+ ZeroCopyInputStream* const* streams_;
+ int stream_count_;
+ int64 bytes_retired_; // Bytes read from previous streams.
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which wraps some other stream and limits it to
+// a particular byte count.
+class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
+ public:
+ LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
+ ~LimitingInputStream();
+
+ // implements ZeroCopyInputStream ----------------------------------
+ bool Next(const void** data, int* size);
+ void BackUp(int count);
+ bool Skip(int count);
+ int64 ByteCount() const;
+
+
+ private:
+ ZeroCopyInputStream* input_;
+ int64 limit_; // Decreases as we go, becomes negative if we overshoot.
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
+};
+
+// ===================================================================
+
+} // namespace io
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_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 00000000..c618041f
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -0,0 +1,443 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sstream>
+
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <google/protobuf/stubs/common.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)
+#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 char* 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 char* str);
+ // Writes some text to the output stream in a particular order. Returns
+ // the number of bytes written, incase 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);
+
+ 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;
+ }
+
+ 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;
+ }
+}
+
+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;
+
+ while (true) {
+ if (!input->Next(&in, &in_size)) {
+ return size - out_size;
+ }
+
+ if (out_size <= in_size) {
+ memcpy(out, in, 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 char* str) {
+ EXPECT_TRUE(WriteToOutput(output, str, strlen(str)));
+}
+
+void IoTest::ReadString(ZeroCopyInputStream* input, const char* str) {
+ int length = strlen(str);
+ scoped_array<char> buffer(new char[length + 1]);
+ buffer[length] = '\0';
+ EXPECT_EQ(ReadFromInput(input, buffer.get(), length), length);
+ EXPECT_STREQ(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) {
+ 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);
+
+ 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);
+ }
+ }
+ }
+}
+
+// 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) {
+ string str;
+ {
+ StringOutputStream output(&str);
+ WriteStuff(&output);
+ }
+ {
+ ArrayInputStream input(str.data(), str.size());
+ ReadStuff(&input);
+ }
+}
+
+
+// To test files, we create a temporary file, write, read, truncate, repeat.
+TEST_F(IoTest, FileIo) {
+ 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);
+ }
+ }
+}
+
+// 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:
+#ifdef _MSC_VER
+ 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++) {
+ stringstream stream;
+
+ {
+ OstreamOutputStream output(&stream, kBlockSizes[i]);
+ WriteStuff(&output);
+ EXPECT_FALSE(stream.fail());
+ }
+
+ {
+ IstreamInputStream input(&stream, kBlockSizes[j]);
+ ReadStuff(&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);
+}
+
+// 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/message.cc b/src/google/protobuf/message.cc
new file mode 100644
index 00000000..f740ef18
--- /dev/null
+++ b/src/google/protobuf/message.cc
@@ -0,0 +1,345 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <stack>
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/message.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.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map-util.h>
+
+namespace google {
+namespace protobuf {
+
+using internal::WireFormat;
+using internal::ReflectionOps;
+
+static string InitializationErrorMessage(const char* action,
+ const Message& message) {
+ return strings::Substitute(
+ "Can't $0 message of type \"$1\" because it is missing required "
+ "fields: $2",
+ action, message.GetDescriptor()->full_name(),
+ message.InitializationErrorString());
+}
+
+Message::~Message() {}
+Message::Reflection::~Reflection() {}
+
+void Message::MergeFrom(const Message& from) {
+ const Descriptor* descriptor = GetDescriptor();
+ GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
+ << ": Tried to merge from a message with a different type. "
+ "to: " << descriptor->full_name() << ", "
+ "from:" << from.GetDescriptor()->full_name();
+ ReflectionOps::Merge(descriptor, *from.GetReflection(), GetReflection());
+}
+
+void Message::CopyFrom(const Message& 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();
+ ReflectionOps::Copy(descriptor, *from.GetReflection(), GetReflection());
+}
+
+void Message::Clear() {
+ ReflectionOps::Clear(GetDescriptor(), GetReflection());
+}
+
+bool Message::IsInitialized() const {
+ return ReflectionOps::IsInitialized(GetDescriptor(), *GetReflection());
+}
+
+void Message::FindInitializationErrors(vector<string>* errors) const {
+ return ReflectionOps::FindInitializationErrors(
+ GetDescriptor(), *GetReflection(), "", errors);
+}
+
+string Message::InitializationErrorString() const {
+ vector<string> errors;
+ FindInitializationErrors(&errors);
+ return JoinStrings(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(GetDescriptor(), GetReflection());
+}
+
+bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
+ return WireFormat::ParseAndMergePartial(
+ GetDescriptor(), input, GetReflection());
+}
+
+bool Message::MergeFromCodedStream(io::CodedInputStream* input) {
+ if (!MergePartialFromCodedStream(input)) return false;
+ if (!IsInitialized()) {
+ GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+ return false;
+ }
+ return true;
+}
+
+bool Message::ParseFromCodedStream(io::CodedInputStream* input) {
+ Clear();
+ return MergeFromCodedStream(input);
+}
+
+bool Message::ParsePartialFromCodedStream(io::CodedInputStream* input) {
+ Clear();
+ return MergePartialFromCodedStream(input);
+}
+
+bool Message::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+ io::CodedInputStream decoder(input);
+ return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
+}
+
+bool Message::ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+ io::CodedInputStream decoder(input);
+ return ParsePartialFromCodedStream(&decoder) &&
+ decoder.ConsumedEntireMessage();
+}
+
+bool Message::ParseFromString(const string& data) {
+ io::ArrayInputStream input(data.data(), data.size());
+ return ParseFromZeroCopyStream(&input);
+}
+
+bool Message::ParsePartialFromString(const string& data) {
+ io::ArrayInputStream input(data.data(), data.size());
+ return ParsePartialFromZeroCopyStream(&input);
+}
+
+bool Message::ParseFromArray(const void* data, int size) {
+ io::ArrayInputStream input(data, size);
+ return ParseFromZeroCopyStream(&input);
+}
+
+bool Message::ParsePartialFromArray(const void* data, int size) {
+ io::ArrayInputStream input(data, size);
+ return ParsePartialFromZeroCopyStream(&input);
+}
+
+bool Message::ParseFromFileDescriptor(int file_descriptor) {
+ io::FileInputStream input(file_descriptor);
+ return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
+ io::FileInputStream input(file_descriptor);
+ return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool Message::ParseFromIstream(istream* input) {
+ io::IstreamInputStream zero_copy_input(input);
+ return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool Message::ParsePartialFromIstream(istream* input) {
+ io::IstreamInputStream zero_copy_input(input);
+ return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+
+
+bool Message::SerializeWithCachedSizes(
+ io::CodedOutputStream* output) const {
+ return WireFormat::SerializeWithCachedSizes(
+ GetDescriptor(), GetReflection(), GetCachedSize(), output);
+}
+
+int Message::ByteSize() const {
+ int size = WireFormat::ByteSize(GetDescriptor(), GetReflection());
+ SetCachedSize(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.";
+}
+
+bool Message::SerializeToCodedStream(io::CodedOutputStream* output) const {
+ GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+ return SerializePartialToCodedStream(output);
+}
+
+bool Message::SerializePartialToCodedStream(
+ io::CodedOutputStream* output) const {
+ ByteSize(); // Force size to be cached.
+ if (!SerializeWithCachedSizes(output)) return false;
+ return true;
+}
+
+bool Message::SerializeToZeroCopyStream(
+ io::ZeroCopyOutputStream* output) const {
+ io::CodedOutputStream encoder(output);
+ return SerializeToCodedStream(&encoder);
+}
+
+bool Message::SerializePartialToZeroCopyStream(
+ io::ZeroCopyOutputStream* output) const {
+ io::CodedOutputStream encoder(output);
+ return SerializePartialToCodedStream(&encoder);
+}
+
+bool Message::AppendToString(string* output) const {
+ GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+ return AppendPartialToString(output);
+}
+
+bool Message::AppendPartialToString(string* output) const {
+ // For efficiency, we'd like to reserve the exact amount of space we need
+ // in the string.
+ int total_size = output->size() + ByteSize();
+ output->reserve(total_size);
+
+ io::StringOutputStream output_stream(output);
+
+ {
+ io::CodedOutputStream encoder(&output_stream);
+ if (!SerializeWithCachedSizes(&encoder)) return false;
+ }
+
+ GOOGLE_CHECK_EQ(output_stream.ByteCount(), total_size);
+ return true;
+}
+
+bool Message::SerializeToString(string* output) const {
+ output->clear();
+ return AppendToString(output);
+}
+
+bool Message::SerializePartialToString(string* output) const {
+ output->clear();
+ return AppendPartialToString(output);
+}
+
+bool Message::SerializeToArray(void* data, int size) const {
+ io::ArrayOutputStream output_stream(data, size);
+ return SerializeToZeroCopyStream(&output_stream);
+}
+
+bool Message::SerializePartialToArray(void* data, int size) const {
+ io::ArrayOutputStream output_stream(data, size);
+ return SerializePartialToZeroCopyStream(&output_stream);
+}
+
+bool Message::SerializeToFileDescriptor(int file_descriptor) const {
+ io::FileOutputStream output(file_descriptor);
+ return SerializeToZeroCopyStream(&output);
+}
+
+bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
+ io::FileOutputStream output(file_descriptor);
+ return SerializePartialToZeroCopyStream(&output);
+}
+
+bool Message::SerializeToOstream(ostream* output) const {
+ io::OstreamOutputStream zero_copy_output(output);
+ return SerializeToZeroCopyStream(&zero_copy_output);
+}
+
+bool Message::SerializePartialToOstream(ostream* output) const {
+ io::OstreamOutputStream zero_copy_output(output);
+ return SerializePartialToZeroCopyStream(&zero_copy_output);
+}
+
+
+// ===================================================================
+// MessageFactory
+
+MessageFactory::~MessageFactory() {}
+
+namespace {
+
+class GeneratedMessageFactory : public MessageFactory {
+ public:
+ GeneratedMessageFactory();
+ ~GeneratedMessageFactory();
+
+ static GeneratedMessageFactory* singleton();
+
+ void RegisterType(const Descriptor* descriptor, const Message* prototype);
+
+ // implements MessageFactory ---------------------------------------
+ const Message* GetPrototype(const Descriptor* type);
+
+ private:
+ hash_map<const Descriptor*, const Message*> type_map_;
+};
+
+GeneratedMessageFactory::GeneratedMessageFactory() {}
+GeneratedMessageFactory::~GeneratedMessageFactory() {}
+
+GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
+ // No need for thread-safety here because this will be called at static
+ // initialization time. (And GCC4 makes this thread-safe anyway.)
+ static GeneratedMessageFactory singleton;
+ return &singleton;
+}
+
+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.";
+
+ if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
+ GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
+ }
+}
+
+const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
+ return FindPtrOrNull(type_map_, type);
+}
+
+} // namespace
+
+MessageFactory* MessageFactory::generated_factory() {
+ return GeneratedMessageFactory::singleton();
+}
+
+void MessageFactory::InternalRegisterGeneratedMessage(
+ const Descriptor* descriptor, const Message* prototype) {
+ GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
+}
+
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
new file mode 100644
index 00000000..2c2cf5bd
--- /dev/null
+++ b/src/google/protobuf/message.h
@@ -0,0 +1,624 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains the abstract interface for all protocol messages.
+// 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:
+//
+// 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;
+// Descriptor* descriptor = foo->GetDescriptor();
+//
+// // Get the descriptors for the fields we're interested in and verify
+// // their types.
+// FieldDescriptor* text_field = descriptor->FindFieldByName("text");
+// assert(text_field != NULL);
+// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
+// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL);
+// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers");
+// assert(numbers_field != NULL);
+// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
+// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED);
+//
+// // Parse the message.
+// foo->ParseFromString(data);
+//
+// // Use the reflection interface to examine the contents.
+// Message::Reflection* reflection = foo->GetReflection();
+// assert(reflection->GetString(text_field) == "Hello World!");
+// assert(reflection->CountField(numbers_field) == 3);
+// assert(reflection->GetInt32(numbers_field, 0) == 1);
+// assert(reflection->GetInt32(numbers_field, 1) == 5);
+// assert(reflection->GetInt32(numbers_field, 2) == 42);
+//
+// delete foo;
+// }
+
+#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
+#define GOOGLE_PROTOBUF_MESSAGE_H__
+
+#include <vector>
+#include <string>
+#include <iosfwd>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+
+namespace protobuf {
+
+// Defined in this file.
+class Message;
+
+// Defined in other files.
+class Descriptor; // descriptor.h
+class FieldDescriptor; // descriptor.h
+class EnumValueDescriptor; // descriptor.h
+namespace io {
+ class ZeroCopyInputStream; // zero_copy_stream.h
+ class ZeroCopyOutputStream; // zero_copy_stream.h
+ class CodedInputStream; // coded_stream.h
+ class CodedOutputStream; // coded_stream.h
+}
+class UnknownFieldSet; // unknown_field_set.h
+
+// Abstract interface for protocol messages.
+//
+// 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.
+class LIBPROTOBUF_EXPORT Message {
+ public:
+ inline Message() {}
+ virtual ~Message();
+
+ // Basic Operations ------------------------------------------------
+
+ // Construct a new instance of the same type. Ownership is passed to the
+ // caller.
+ virtual Message* New() const = 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);".
+ virtual void CopyFrom(const Message& from);
+
+ // Merge the fields from the given message into this message. Singular
+ // fields will be overwritten, 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);
+
+ // Clear all fields of the message and set them to their default values.
+ // Clear() avoids freeing memory, assuming that any memory allocated
+ // to hold parts of the message will be needed again to hold the next
+ // message. If you actually want to free the memory used by a Message,
+ // you must delete it.
+ virtual void Clear();
+
+ // Quickly check if all required fields have values set.
+ virtual bool IsInitialized() const;
+
+ // 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(vector<string>* errors) const;
+
+ // Like FindInitializationErrors, but joins all the strings, delimited by
+ // commas, and returns them.
+ string InitializationErrorString() const;
+
+ // 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.
+ virtual void DiscardUnknownFields();
+
+ // Debugging -------------------------------------------------------
+
+ // Generates a human readable form of this message, useful for debugging
+ // and other purposes.
+ string DebugString() const;
+ // Like DebugString(), but with less whitespace.
+ string ShortDebugString() const;
+ // Convenience function useful in GDB. Prints DebugString() to stdout.
+ void PrintDebugString() const;
+
+ // Parsing ---------------------------------------------------------
+ // Methods for parsing in protocol buffer format. Most of these are
+ // just simple wrappers around MergeFromCodedStream().
+
+ // 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.
+ bool ParseFromCodedStream(io::CodedInputStream* input);
+ // Like ParseFromCodedStream(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromCodedStream(io::CodedInputStream* input);
+ // Read a protocol buffer from the given zero-copy input stream. If
+ // successful, the entire input will be consumed.
+ bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
+ // Like ParseFromZeroCopyStream(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
+ // Parse a protocol buffer contained in a string.
+ bool ParseFromString(const string& data);
+ // Like ParseFromString(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromString(const string& data);
+ // Parse a protocol buffer contained in an array of bytes.
+ bool ParseFromArray(const void* data, int size);
+ // Like ParseFromArray(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromArray(const void* data, int size);
+
+ // Parse a protocol buffer from a file descriptor. If successful, the entire
+ // input will be consumed.
+ bool ParseFromFileDescriptor(int file_descriptor);
+ // Like ParseFromFileDescriptor(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromFileDescriptor(int file_descriptor);
+ // Parse a protocol buffer from a C++ istream. If successful, the entire
+ // input will be consumed.
+ bool ParseFromIstream(istream* input);
+ // Like ParseFromIstream(), but accepts messages that are missing
+ // required fields.
+ bool ParsePartialFromIstream(istream* input);
+
+
+ // Reads a protocol buffer from the stream and merges it into this
+ // Message. Singular fields read from the input overwrite 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().
+ virtual bool MergePartialFromCodedStream(io::CodedInputStream* input);
+
+ // 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(string* output) const;
+ // Like SerializeToString(), but allows missing required fields.
+ bool SerializePartialToString(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;
+
+ // 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(ostream* output) const;
+ // Like SerializeToOstream(), but allows missing required fields.
+ bool SerializePartialToOstream(ostream* output) const;
+
+
+ // Like SerializeToString(), but appends to the data to the string's existing
+ // contents. All required fields must be set.
+ bool AppendToString(string* output) const;
+ // Like AppendToString(), but allows missing required fields.
+ bool AppendPartialToString(string* output) const;
+
+ // Computes the serialized size of the message. This recursively calls
+ // ByteSize() on all embedded messages. If a subclass does not override
+ // this, it MUST override SetCachedSize().
+ virtual int ByteSize() const;
+
+ // Serializes the message without recomputing the size. The message must
+ // not have changed since the last call to ByteSize(); if it has, the results
+ // are undefined.
+ virtual bool SerializeWithCachedSizes(io::CodedOutputStream* output) 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;
+
+ 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 ---------------------------------------------------
+
+ class Reflection; // Defined below.
+
+ // Get a Descriptor for this message's type. This describes what
+ // fields the message contains, the types of those fields, etc.
+ virtual const Descriptor* GetDescriptor() const = 0;
+
+ // Get 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.
+ virtual const Reflection* GetReflection() const = 0;
+
+ // Get 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.
+ virtual Reflection* GetReflection() = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
+};
+
+// 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).
+//
+// 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.
+//
+// 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.
+//
+// TODO(kenton): Create a utility class which callers can use to read and
+// write fields from a Reflection without paying attention to the type.
+class LIBPROTOBUF_EXPORT Message::Reflection {
+ public:
+ inline Reflection() {}
+ virtual ~Reflection();
+
+ // 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.
+ virtual const UnknownFieldSet& GetUnknownFields() const = 0;
+ // Get a mutable pointer to the UnknownFieldSet for the message. This
+ // contains fields which were seen when the Message was parsed but were not
+ // recognized according to the Message's definition.
+ virtual UnknownFieldSet* MutableUnknownFields() = 0;
+
+ // Check if the given non-repeated field is set.
+ virtual bool HasField(const FieldDescriptor* field) const = 0;
+
+ // Get the number of elements of a repeated field.
+ virtual int FieldSize(const FieldDescriptor* field) const = 0;
+
+ // Clear the value of a field, so that HasField() returns false or
+ // FieldSize() returns zero.
+ virtual void ClearField(const FieldDescriptor* field) = 0;
+
+ // List all fields of the message which are currently set. This includes
+ // extensions. 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.
+ virtual void ListFields(vector<const FieldDescriptor*>* output) const = 0;
+
+ // Singular field getters ------------------------------------------
+ // These get the value of a non-repeated field. They return the default
+ // value for fields that aren't set.
+
+ virtual int32 GetInt32 (const FieldDescriptor* field) const = 0;
+ virtual int64 GetInt64 (const FieldDescriptor* field) const = 0;
+ virtual uint32 GetUInt32(const FieldDescriptor* field) const = 0;
+ virtual uint64 GetUInt64(const FieldDescriptor* field) const = 0;
+ virtual float GetFloat (const FieldDescriptor* field) const = 0;
+ virtual double GetDouble(const FieldDescriptor* field) const = 0;
+ virtual bool GetBool (const FieldDescriptor* field) const = 0;
+ virtual string GetString(const FieldDescriptor* field) const = 0;
+ virtual const EnumValueDescriptor* GetEnum(
+ const FieldDescriptor* field) const = 0;
+ virtual const Message& GetMessage(const FieldDescriptor* field) const = 0;
+
+ // Get a string value without copying, if possible.
+ //
+ // GetString() necessarily returns a copy of the string. This can be
+ // inefficient when the string is already stored in a string object in the
+ // underlying message. GetStringReference() will return a reference to the
+ // underlying 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(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:
+ // string str = reflection->GetString(field);
+ virtual const string& GetStringReference(const FieldDescriptor* field,
+ string* scratch) const = 0;
+
+
+ // Singular field mutators -----------------------------------------
+ // These mutate the value of a non-repeated field.
+
+ virtual void SetInt32 (const FieldDescriptor* field, int32 value) = 0;
+ virtual void SetInt64 (const FieldDescriptor* field, int64 value) = 0;
+ virtual void SetUInt32(const FieldDescriptor* field, uint32 value) = 0;
+ virtual void SetUInt64(const FieldDescriptor* field, uint64 value) = 0;
+ virtual void SetFloat (const FieldDescriptor* field, float value) = 0;
+ virtual void SetDouble(const FieldDescriptor* field, double value) = 0;
+ virtual void SetBool (const FieldDescriptor* field, bool value) = 0;
+ virtual void SetString(const FieldDescriptor* field, const string& value) = 0;
+ virtual void SetEnum (const FieldDescriptor* field,
+ const EnumValueDescriptor* value) = 0;
+ // Get a mutable pointer to a field with a message type.
+ virtual Message* MutableMessage(const FieldDescriptor* field) = 0;
+
+
+ // Repeated field getters ------------------------------------------
+ // These get the value of one element of a repeated field.
+
+ virtual int32 GetRepeatedInt32 (const FieldDescriptor* field,
+ int index) const = 0;
+ virtual int64 GetRepeatedInt64 (const FieldDescriptor* field,
+ int index) const = 0;
+ virtual uint32 GetRepeatedUInt32(const FieldDescriptor* field,
+ int index) const = 0;
+ virtual uint64 GetRepeatedUInt64(const FieldDescriptor* field,
+ int index) const = 0;
+ virtual float GetRepeatedFloat (const FieldDescriptor* field,
+ int index) const = 0;
+ virtual double GetRepeatedDouble(const FieldDescriptor* field,
+ int index) const = 0;
+ virtual bool GetRepeatedBool (const FieldDescriptor* field,
+ int index) const = 0;
+ virtual string GetRepeatedString(const FieldDescriptor* field,
+ int index) const = 0;
+ virtual const EnumValueDescriptor* GetRepeatedEnum(
+ const FieldDescriptor* field, int index) const = 0;
+ virtual const Message& GetRepeatedMessage(
+ const FieldDescriptor* field, int index) const = 0;
+
+ // See GetStringReference(), above.
+ virtual const string& GetRepeatedStringReference(
+ const FieldDescriptor* field, int index,
+ string* scratch) const = 0;
+
+
+ // Repeated field mutators -----------------------------------------
+ // These mutate the value of one element of a repeated field.
+
+ virtual void SetRepeatedInt32 (const FieldDescriptor* field,
+ int index, int32 value) = 0;
+ virtual void SetRepeatedInt64 (const FieldDescriptor* field,
+ int index, int64 value) = 0;
+ virtual void SetRepeatedUInt32(const FieldDescriptor* field,
+ int index, uint32 value) = 0;
+ virtual void SetRepeatedUInt64(const FieldDescriptor* field,
+ int index, uint64 value) = 0;
+ virtual void SetRepeatedFloat (const FieldDescriptor* field,
+ int index, float value) = 0;
+ virtual void SetRepeatedDouble(const FieldDescriptor* field,
+ int index, double value) = 0;
+ virtual void SetRepeatedBool (const FieldDescriptor* field,
+ int index, bool value) = 0;
+ virtual void SetRepeatedString(const FieldDescriptor* field,
+ int index, const string& value) = 0;
+ virtual void SetRepeatedEnum(const FieldDescriptor* field,
+ int index, const EnumValueDescriptor* value) = 0;
+ // Get a mutable pointer to an element of a repeated field with a message
+ // type.
+ virtual Message* MutableRepeatedMessage(
+ const FieldDescriptor* field, int index) = 0;
+
+
+ // Repeated field adders -------------------------------------------
+ // These add an element to a repeated field.
+
+ virtual void AddInt32 (const FieldDescriptor* field, int32 value) = 0;
+ virtual void AddInt64 (const FieldDescriptor* field, int64 value) = 0;
+ virtual void AddUInt32(const FieldDescriptor* field, uint32 value) = 0;
+ virtual void AddUInt64(const FieldDescriptor* field, uint64 value) = 0;
+ virtual void AddFloat (const FieldDescriptor* field, float value) = 0;
+ virtual void AddDouble(const FieldDescriptor* field, double value) = 0;
+ virtual void AddBool (const FieldDescriptor* field, bool value) = 0;
+ virtual void AddString(const FieldDescriptor* field, const string& value) = 0;
+ virtual void AddEnum (const FieldDescriptor* field,
+ const EnumValueDescriptor* value) = 0;
+ virtual Message* AddMessage(const FieldDescriptor* field) = 0;
+
+
+ // Extensions ------------------------------------------------------
+
+ // Try to find an extension of this message type by fully-qualified field
+ // name. Returns NULL if no extension is known for this name or number.
+ virtual const FieldDescriptor* FindKnownExtensionByName(
+ const string& name) const = 0;
+
+ // Try to find an extension of this message type by field number.
+ // Returns NULL if no extension is known for this name or number.
+ virtual const FieldDescriptor* FindKnownExtensionByNumber(
+ int number) const = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
+};
+
+// Abstract interface for a factory for message objects.
+class LIBPROTOBUF_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 destoyed 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 NULL 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 NULL. (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 message type at static initialization
+ // time, to be placed in generated_factory().
+ static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
+ const Message* prototype);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_MESSAGE_H__
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
new file mode 100644
index 00000000..491d3799
--- /dev/null
+++ b/src/google/protobuf/message_unittest.cc
@@ -0,0 +1,224 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <sstream>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+#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(MessageTest, SerializeHelpers) {
+ // TODO(kenton): Test more helpers? They're all two-liners so it seems
+ // like a waste of time.
+
+ protobuf_unittest::TestAllTypes message;
+ TestUtil::SetAllFields(&message);
+ stringstream stream;
+
+ string str1("foo");
+ string str2("bar");
+
+ message.SerializeToString(&str1);
+ message.AppendToString(&str2);
+ 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.
+ string temp = stream.str();
+ EXPECT_TRUE(temp == str1);
+
+}
+
+TEST(MessageTest, ParseFromFileDescriptor) {
+ string filename = TestSourceDir() +
+ "/google/protobuf/testdata/golden_message";
+ int file = open(filename.c_str(), O_RDONLY | O_BINARY);
+
+ unittest::TestAllTypes message;
+ EXPECT_TRUE(message.ParseFromFileDescriptor(file));
+ TestUtil::ExpectAllFieldsSet(message);
+
+ EXPECT_GE(close(file), 0);
+}
+
+TEST(MessageTest, ParseHelpers) {
+ // TODO(kenton): Test more helpers? They're all two-liners so it seems
+ // like a waste of time.
+ string data;
+
+ {
+ // Set up.
+ protobuf_unittest::TestAllTypes message;
+ TestUtil::SetAllFields(&message);
+ message.SerializeToString(&data);
+ }
+
+ {
+ // Test ParseFromString.
+ protobuf_unittest::TestAllTypes message;
+ EXPECT_TRUE(message.ParseFromString(data));
+ TestUtil::ExpectAllFieldsSet(message);
+ }
+
+ {
+ // Test ParseFromIstream.
+ protobuf_unittest::TestAllTypes message;
+ stringstream stream(data);
+ EXPECT_TRUE(message.ParseFromIstream(&stream));
+ EXPECT_TRUE(stream.eof());
+ TestUtil::ExpectAllFieldsSet(message);
+ }
+}
+
+TEST(MessageTest, ParseFailsIfNotInitialized) {
+ unittest::TestRequired message;
+ vector<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 \"protobuf_unittest.TestRequired\" "
+ "because it is missing required fields: a, b, c",
+ errors[0]);
+}
+
+TEST(MessageTest, BypassInitializationCheckOnParse) {
+ unittest::TestRequired message;
+ io::ArrayInputStream raw_input(NULL, 0);
+ io::CodedInputStream input(&raw_input);
+ EXPECT_TRUE(message.MergePartialFromCodedStream(&input));
+}
+
+TEST(MessageTest, InitializationErrorString) {
+ unittest::TestRequired message;
+ EXPECT_EQ("a, b, c", message.InitializationErrorString());
+}
+
+#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet.
+
+TEST(MessageTest, SerializeFailsIfNotInitialized) {
+ unittest::TestRequired message;
+ string data;
+ EXPECT_DEBUG_DEATH(EXPECT_TRUE(message.SerializeToString(&data)),
+ "Can't serialize message of type \"protobuf_unittest.TestRequired\" because "
+ "it is missing required fields: a, b, c");
+}
+
+TEST(MessageTest, CheckInitialized) {
+ unittest::TestRequired message;
+ EXPECT_DEATH(message.CheckInitialized(),
+ "Message of type \"protobuf_unittest.TestRequired\" is missing required "
+ "fields: a, b, c");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(MessageTest, BypassInitializationCheckOnSerialize) {
+ unittest::TestRequired message;
+ io::ArrayOutputStream raw_output(NULL, 0);
+ io::CodedOutputStream output(&raw_output);
+ EXPECT_TRUE(message.SerializePartialToCodedStream(&output));
+}
+
+TEST(MessageTest, FindInitializationErrors) {
+ unittest::TestRequired message;
+ vector<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(MessageTest, 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));
+}
+
+TEST(MessageFactoryTest, GeneratedFactoryLookup) {
+ EXPECT_EQ(
+ MessageFactory::generated_factory()->GetPrototype(
+ protobuf_unittest::TestAllTypes::descriptor()),
+ &protobuf_unittest::TestAllTypes::default_instance());
+}
+
+TEST(MessageFactoryTest, 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 NULL.
+ EXPECT_TRUE(
+ MessageFactory::generated_factory()->GetPrototype(descriptor) == NULL);
+}
+
+} // 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 00000000..0ba6e791
--- /dev/null
+++ b/src/google/protobuf/package_info.h
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+namespace google {
+
+// 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 protobuf {}
+} // namespace google
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
new file mode 100644
index 00000000..2b263298
--- /dev/null
+++ b/src/google/protobuf/reflection_ops.cc
@@ -0,0 +1,241 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/descriptor.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void ReflectionOps::Copy(const Descriptor* descriptor,
+ const Message::Reflection& from,
+ Message::Reflection* to) {
+ if (&from == to) return;
+ Clear(descriptor, to);
+ Merge(descriptor, from, to);
+}
+
+void ReflectionOps::Merge(const Descriptor* descriptor,
+ const Message::Reflection& from,
+ Message::Reflection* to) {
+ GOOGLE_CHECK_NE(&from, to);
+ vector<const FieldDescriptor*> fields;
+ from.ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+
+ if (field->is_repeated()) {
+ int count = from.FieldSize(field);
+ for (int j = 0; j < count; j++) {
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ to->Add##METHOD(field, \
+ from.GetRepeated##METHOD(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:
+ to->AddMessage(field)->MergeFrom(
+ from.GetRepeatedMessage(field, j));
+ break;
+ }
+ }
+ } else if (from.HasField(field)) {
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ to->Set##METHOD(field, from.Get##METHOD(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:
+ to->MutableMessage(field)->MergeFrom(
+ from.GetMessage(field));
+ break;
+ }
+ }
+ }
+
+ to->MutableUnknownFields()->MergeFrom(from.GetUnknownFields());
+}
+
+void ReflectionOps::Clear(const Descriptor* descriptor,
+ Message::Reflection* reflection) {
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ reflection->ClearField(fields[i]);
+ }
+
+ reflection->MutableUnknownFields()->Clear();
+}
+
+bool ReflectionOps::IsInitialized(const Descriptor* descriptor,
+ const Message::Reflection& reflection) {
+ // Check required fields of this message.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ if (descriptor->field(i)->is_required()) {
+ if (!reflection.HasField(descriptor->field(i))) {
+ return false;
+ }
+ }
+ }
+
+ // Check that sub-messages are initialized.
+ vector<const FieldDescriptor*> fields;
+ reflection.ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_repeated()) {
+ int size = reflection.FieldSize(field);
+
+ for (int i = 0; i < size; i++) {
+ if (!reflection.GetRepeatedMessage(field, i).IsInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (reflection.HasField(field) &&
+ !reflection.GetMessage(field).IsInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void ReflectionOps::DiscardUnknownFields(
+ const Descriptor* descriptor,
+ Message::Reflection* reflection) {
+ reflection->MutableUnknownFields()->Clear();
+
+ vector<const FieldDescriptor*> fields;
+ reflection->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_repeated()) {
+ int size = reflection->FieldSize(field);
+ for (int i = 0; i < size; i++) {
+ reflection->MutableRepeatedMessage(field, i)->DiscardUnknownFields();
+ }
+ } else {
+ if (reflection->HasField(field)) {
+ reflection->MutableMessage(field)->DiscardUnknownFields();
+ }
+ }
+ }
+ }
+}
+
+static string SubMessagePrefix(const string& prefix,
+ const FieldDescriptor* field,
+ int index) {
+ 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(SimpleItoa(index));
+ result.append("]");
+ }
+ result.append(".");
+ return result;
+}
+
+void ReflectionOps::FindInitializationErrors(
+ const Descriptor* descriptor,
+ const Message::Reflection& reflection,
+ const string& prefix,
+ vector<string>* errors) {
+ // Check required fields of this message.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ if (descriptor->field(i)->is_required()) {
+ if (!reflection.HasField(descriptor->field(i))) {
+ errors->push_back(prefix + descriptor->field(i)->name());
+ }
+ }
+ }
+
+ // Check sub-messages.
+ vector<const FieldDescriptor*> fields;
+ reflection.ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+ if (field->is_repeated()) {
+ int size = reflection.FieldSize(field);
+
+ for (int i = 0; i < size; i++) {
+ const Message& sub_message = reflection.GetRepeatedMessage(field, i);
+ FindInitializationErrors(field->message_type(),
+ *sub_message.GetReflection(),
+ SubMessagePrefix(prefix, field, i),
+ errors);
+ }
+ } else {
+ if (reflection.HasField(field)) {
+ const Message& sub_message = reflection.GetMessage(field);
+ FindInitializationErrors(field->message_type(),
+ *sub_message.GetReflection(),
+ SubMessagePrefix(prefix, field, -1),
+ errors);
+ }
+ }
+ }
+ }
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/reflection_ops.h b/src/google/protobuf/reflection_ops.h
new file mode 100644
index 00000000..4a7f76bb
--- /dev/null
+++ b/src/google/protobuf/reflection_ops.h
@@ -0,0 +1,74 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/message.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Basic operations that can be performed using Message::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 LIBPROTOBUF_EXPORT ReflectionOps {
+ public:
+ static void Copy(const Descriptor* descriptor,
+ const Message::Reflection& from,
+ Message::Reflection* to);
+ static void Merge(const Descriptor* descriptor,
+ const Message::Reflection& from,
+ Message::Reflection* to);
+ static void Clear(const Descriptor* descriptor,
+ Message::Reflection* reflection);
+ static bool IsInitialized(const Descriptor* descriptor,
+ const Message::Reflection& reflection);
+ static void DiscardUnknownFields(const Descriptor* descriptor,
+ Message::Reflection* reflection);
+
+ // 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 Descriptor* descriptor,
+ const Message::Reflection& reflection,
+ const string& prefix,
+ vector<string>* errors);
+
+ private:
+ // All methods are static. No need to construct.
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
+};
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..e1af2fca
--- /dev/null
+++ b/src/google/protobuf/reflection_ops_unittest.cc
@@ -0,0 +1,421 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/descriptor.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.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.descriptor(), *message.GetReflection(),
+ message2.GetReflection());
+
+ TestUtil::ExpectAllFieldsSet(message2);
+
+ // Copying from self should be a no-op.
+ ReflectionOps::Copy(message2.descriptor(), *message2.GetReflection(),
+ message2.GetReflection());
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(ReflectionOpsTest, CopyExtensions) {
+ unittest::TestAllExtensions message, message2;
+
+ TestUtil::SetAllExtensions(&message);
+
+ ReflectionOps::Copy(message.descriptor(), *message.GetReflection(),
+ message2.GetReflection());
+
+ TestUtil::ExpectAllExtensionsSet(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 i = message.repeated_int32(0);
+ message.clear_repeated_int32();
+ message.add_repeated_int32(i);
+
+ ReflectionOps::Merge(message2.descriptor(), *message2.GetReflection(),
+ message.GetReflection());
+
+ 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 i = message.GetExtension(unittest::repeated_int32_extension, 0);
+ message.ClearExtension(unittest::repeated_int32_extension);
+ message.AddExtension(unittest::repeated_int32_extension, i);
+
+ ReflectionOps::Merge(message2.descriptor(), *message2.GetReflection(),
+ message.GetReflection());
+
+ TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(ReflectionOpsTest, MergeUnknown) {
+ // Test that the messages' UnknownFieldSets are correctly merged.
+ unittest::TestEmptyMessage message1, message2;
+ message1.mutable_unknown_fields()->AddField(1234)->add_varint(1);
+ message2.mutable_unknown_fields()->AddField(1234)->add_varint(2);
+
+ ReflectionOps::Merge(unittest::TestEmptyMessage::descriptor(),
+ *message2.GetReflection(),
+ message1.GetReflection());
+
+ ASSERT_EQ(1, message1.unknown_fields().field_count());
+ const UnknownField& field = message1.unknown_fields().field(0);
+ ASSERT_EQ(2, field.varint_size());
+ EXPECT_EQ(1, field.varint(0));
+ EXPECT_EQ(2, field.varint(1));
+}
+
+#ifdef GTEST_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.descriptor(), *message.GetReflection(),
+ message.GetReflection()),
+ "&from");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(ReflectionOpsTest, Clear) {
+ unittest::TestAllTypes message;
+
+ TestUtil::SetAllFields(&message);
+
+ ReflectionOps::Clear(message.descriptor(), message.GetReflection());
+
+ 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.descriptor(), message.GetReflection());
+
+ 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()->AddField(1234)->add_varint(1);
+
+ ReflectionOps::Clear(message.descriptor(), message.GetReflection());
+
+ EXPECT_EQ(0, message.unknown_fields().field_count());
+}
+
+TEST(ReflectionOpsTest, DiscardUnknownFields) {
+ unittest::TestAllTypes message;
+ TestUtil::SetAllFields(&message);
+
+ // Set some unknown fields in message.
+ message.mutable_unknown_fields()
+ ->AddField(123456)
+ ->add_varint(654321);
+ message.mutable_optional_nested_message()
+ ->mutable_unknown_fields()
+ ->AddField(123456)
+ ->add_varint(654321);
+ message.mutable_repeated_nested_message(0)
+ ->mutable_unknown_fields()
+ ->AddField(123456)
+ ->add_varint(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.GetDescriptor(),
+ message.GetReflection());
+ 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()
+ ->AddField(123456)
+ ->add_varint(654321);
+ message.MutableExtension(unittest::optional_nested_message_extension)
+ ->mutable_unknown_fields()
+ ->AddField(123456)
+ ->add_varint(654321);
+ message.MutableExtension(unittest::repeated_nested_message_extension, 0)
+ ->mutable_unknown_fields()
+ ->AddField(123456)
+ ->add_varint(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.GetDescriptor(),
+ message.GetReflection());
+ 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.descriptor(),
+ *message.GetReflection()));
+ message.set_a(1);
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+ message.set_b(2);
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+ message.set_c(3);
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+}
+
+TEST(ReflectionOpsTest, ForeignIsInitialized) {
+ unittest::TestRequiredForeign message;
+
+ // Starts out initialized because the foreign message is itself an optional
+ // field.
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // Once we create that field, the message is no longer initialized.
+ message.mutable_optional_message();
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // 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.descriptor(),
+ *message.GetReflection()));
+
+ // Add a repeated version of the message. No longer initialized.
+ unittest::TestRequired* sub_message = message.add_repeated_message();
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // Initialize that repeated version.
+ sub_message->set_a(1);
+ sub_message->set_b(2);
+ sub_message->set_c(3);
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+}
+
+TEST(ReflectionOpsTest, ExtensionIsInitialized) {
+ unittest::TestAllExtensions message;
+
+ // Starts out initialized because the foreign message is itself an optional
+ // field.
+ EXPECT_TRUE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // Once we create that field, the message is no longer initialized.
+ message.MutableExtension(unittest::TestRequired::single);
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // 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.descriptor(),
+ *message.GetReflection()));
+
+ // Add a repeated version of the message. No longer initialized.
+ message.AddExtension(unittest::TestRequired::multi);
+ EXPECT_FALSE(ReflectionOps::IsInitialized(message.descriptor(),
+ *message.GetReflection()));
+
+ // 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.descriptor(),
+ *message.GetReflection()));
+}
+
+static string FindInitializationErrors(const Message& message) {
+ vector<string> errors;
+ ReflectionOps::FindInitializationErrors(message.GetDescriptor(),
+ *message.GetReflection(),
+ "", &errors);
+ return JoinStrings(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));
+}
+
+} // namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
new file mode 100644
index 00000000..53a3c958
--- /dev/null
+++ b/src/google/protobuf/repeated_field.cc
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+GenericRepeatedField::~GenericRepeatedField() {}
+
+} // namespace internal
+
+template <>
+void RepeatedPtrField<string>::Clear() {
+ for (int i = 0; i < current_size_; i++) {
+ elements_[i]->clear();
+ }
+ current_size_ = 0;
+}
+
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
new file mode 100644
index 00000000..3368e8b7
--- /dev/null
+++ b/src/google/protobuf/repeated_field.h
@@ -0,0 +1,782 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+//
+// Typically, clients should not need to access RepeatedField objects directly,
+// but should instead use the accessor functions generated automatically by the
+// protocol compiler.
+
+#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+
+#include <string>
+#include <iterator>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message.h>
+
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+// DO NOT USE GenericRepeatedField; it should be considered a private detail
+// of RepeatedField/RepeatedPtrField that may be removed in the future.
+// GeneratedMessageReflection needs to manipulate repeated fields in a
+// generic way, so we have them implement this interface. This should ONLY
+// be used by GeneratedMessageReflection. This would normally be very bad
+// design but GeneratedMessageReflection is a big efficiency hack anyway.
+//
+// TODO(kenton): Implement something like Jeff's ProtoVoidPtrArray change.
+// Then, get rid of GenericRepeatedField.
+class LIBPROTOBUF_EXPORT GenericRepeatedField {
+ public:
+ inline GenericRepeatedField() {}
+ virtual ~GenericRepeatedField();
+
+ private:
+ // We only want GeneratedMessageReflection to see and use these, so we
+ // make them private. Yes, it is valid C++ for a subclass to implement
+ // a virtual method which is private in the superclass. Crazy, huh?
+ friend class GeneratedMessageReflection;
+
+ virtual const void* GenericGet(int index) const = 0;
+ virtual void* GenericMutable(int index) = 0;
+ virtual void* GenericAdd() = 0;
+ virtual void GenericClear() = 0;
+ virtual int GenericSize() const = 0;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GenericRepeatedField);
+};
+
+} // 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 : public internal::GenericRepeatedField {
+ public:
+ RepeatedField();
+ ~RepeatedField();
+
+ int size() const;
+
+ Element Get(int index) const;
+ Element* Mutable(int index);
+ void Set(int index, Element value);
+ void Add(Element value);
+ // Remove the last element in the array.
+ // 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
+ // so that the one you want removed is at the end, then call RemoveLast().
+ void RemoveLast();
+ void Clear();
+ void MergeFrom(const RepeatedField& other);
+
+ // Reserve 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);
+
+ // Gets the underlying array. This pointer is possibly invalidated by
+ // any add or remove operation.
+ Element* mutable_data();
+ const Element* data() const;
+
+ // Swap entire contents with "other".
+ void Swap(RepeatedField* other);
+
+ // STL-like iterator support
+ typedef Element* iterator;
+ typedef const Element* const_iterator;
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ private: // See GenericRepeatedField for why this is private.
+ // implements GenericRepeatedField ---------------------------------
+ const void* GenericGet(int index) const;
+ void* GenericMutable(int index);
+ void* GenericAdd();
+ void GenericClear();
+ int GenericSize() const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedField);
+
+ static const int kInitialSize = 4;
+
+ Element* elements_;
+ int current_size_;
+ int total_size_;
+
+ Element initial_space_[kInitialSize];
+};
+
+namespace internal {
+template <typename It> class RepeatedPtrIterator;
+} // namespace internal
+
+// RepeatedPtrField is like RepeatedField, but used for repeated strings or
+// Messages.
+template <typename Element>
+class RepeatedPtrField : public internal::GenericRepeatedField {
+ public:
+ RepeatedPtrField();
+
+ // This constructor is only defined for RepeatedPtrField<Message>.
+ // When a RepeatedPtrField is created using this constructor,
+ // prototype->New() will be called to allocate new elements, rather than
+ // just using the "new" operator. This is useful for the implementation
+ // of DynamicMessage, but is not used by normal generated messages.
+ explicit RepeatedPtrField(const Message* prototype);
+
+ ~RepeatedPtrField();
+
+ // Returns the prototype if one was passed to the constructor.
+ const Message* prototype() const;
+
+ int size() const;
+
+ const Element& Get(int index) const;
+ Element* Mutable(int index);
+ Element* Add();
+ void RemoveLast(); // Remove the last element in the array.
+ void Clear();
+ void MergeFrom(const RepeatedPtrField& other);
+
+ // Reserve 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);
+
+ // Gets the underlying array. This pointer is possibly invalidated by
+ // any add or remove operation.
+ Element** mutable_data();
+ const Element* const* data() const;
+
+ // Swap entire contents with "other".
+ void Swap(RepeatedPtrField* other);
+
+ // STL-like iterator support
+ typedef internal::RepeatedPtrIterator<Element**> iterator;
+ typedef internal::RepeatedPtrIterator<const Element* const*> const_iterator;
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ // Advanced memory management --------------------------------------
+ // When hardcore memory management becomes necessary -- as it often
+ // does here at Google -- the following methods may be useful.
+
+ // Add an already-allocated object, passing ownership to the
+ // RepeatedPtrField.
+ void AddAllocated(Element* value);
+ // Remove the last element and return it, passing ownership to the
+ // caller.
+ // Requires: size() > 0
+ Element* ReleaseLast();
+
+ // 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.
+ //
+ // Really, extremely hardcore programs may actually want to manipulate
+ // these objects to better-optimize memory management. These methods
+ // allow that.
+
+ // Get the number of cleared objects that are currently being kept
+ // around for reuse.
+ int ClearedCount();
+ // Add an element to the pool of cleared objects, passing ownership to
+ // the RepeatedPtrField. The element must be cleared prior to calling
+ // this method.
+ void AddCleared(Element* value);
+ // Remove a single element from the cleared pool and return it, passing
+ // ownership to the caller. The element is guaranteed to be cleared.
+ // Requires: ClearedCount() > 0
+ Element* ReleaseCleared();
+
+ private: // See GenericRepeatedField for why this is private.
+ // implements GenericRepeatedField ---------------------------------
+ const void* GenericGet(int index) const;
+ void* GenericMutable(int index);
+ void* GenericAdd();
+ void GenericClear();
+ int GenericSize() const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField);
+
+ static const int kInitialSize = 4;
+
+ // prototype_ is used for RepeatedPtrField<Message> only (see constructor).
+ const Message* prototype_;
+
+ Element** elements_;
+ int current_size_;
+ int allocated_size_;
+ int total_size_;
+
+ Element* initial_space_[kInitialSize];
+
+ Element* NewElement();
+};
+
+// implementation ====================================================
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField()
+ : elements_(initial_space_),
+ current_size_(0),
+ total_size_(kInitialSize) {
+}
+
+template <typename Element>
+RepeatedField<Element>::~RepeatedField() {
+ if (elements_ != initial_space_) {
+ delete [] elements_;
+ }
+}
+
+template <typename Element>
+inline int RepeatedField<Element>::size() const {
+ return current_size_;
+}
+
+
+template <typename Element>
+inline Element RepeatedField<Element>::Get(int index) const {
+ GOOGLE_DCHECK_LT(index, size());
+ return elements_[index];
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::Mutable(int index) {
+ GOOGLE_DCHECK_LT(index, size());
+ return elements_ + index;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Set(int index, Element value) {
+ GOOGLE_DCHECK_LT(index, size());
+ elements_[index] = value;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Add(Element value) {
+ if (current_size_ == total_size_) Reserve(total_size_ + 1);
+ elements_[current_size_++] = value;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::RemoveLast() {
+ GOOGLE_DCHECK_GT(current_size_, 0);
+ --current_size_;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Clear() {
+ current_size_ = 0;
+}
+
+template <typename Element>
+void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
+ Reserve(current_size_ + other.current_size_);
+ memcpy(elements_ + current_size_, other.elements_,
+ sizeof(Element) * other.current_size_);
+ current_size_ += other.current_size_;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::mutable_data() {
+ return elements_;
+}
+
+template <typename Element>
+inline const Element* RepeatedField<Element>::data() const {
+ return elements_;
+}
+
+
+template <typename Element>
+void RepeatedField<Element>::Swap(RepeatedField* other) {
+ Element* swap_elements = elements_;
+ int swap_current_size = current_size_;
+ int swap_total_size = total_size_;
+ // We may not be using initial_space_ but it's not worth checking. Just
+ // copy it anyway.
+ Element swap_initial_space[kInitialSize];
+ memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
+
+ elements_ = other->elements_;
+ current_size_ = other->current_size_;
+ total_size_ = other->total_size_;
+ memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
+
+ other->elements_ = swap_elements;
+ other->current_size_ = swap_current_size;
+ other->total_size_ = swap_total_size;
+ memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
+
+ if (elements_ == other->initial_space_) {
+ elements_ = initial_space_;
+ }
+ if (other->elements_ == initial_space_) {
+ other->elements_ = other->initial_space_;
+ }
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator
+RepeatedField<Element>::begin() {
+ return elements_;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::begin() const {
+ return elements_;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::iterator
+RepeatedField<Element>::end() {
+ return elements_ + current_size_;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::end() const {
+ return elements_ + current_size_;
+}
+
+
+template <typename Element>
+const void* RepeatedField<Element>::GenericGet(int index) const {
+ GOOGLE_DCHECK_LT(index, size());
+ return elements_ + index;
+}
+
+template <typename Element>
+void* RepeatedField<Element>::GenericMutable(int index) {
+ return Mutable(index);
+}
+
+template <typename Element>
+void* RepeatedField<Element>::GenericAdd() {
+ Add(Element());
+ return Mutable(current_size_ - 1);
+}
+
+template <typename Element>
+void RepeatedField<Element>::GenericClear() {
+ Clear();
+}
+
+template <typename Element>
+int RepeatedField<Element>::GenericSize() const {
+ return size();
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Reserve(int new_size) {
+ if (total_size_ >= new_size) return;
+
+ Element* old_elements = elements_;
+ total_size_ = max(total_size_ * 2, new_size);
+ elements_ = new Element[total_size_];
+ memcpy(elements_, old_elements, current_size_ * sizeof(elements_[0]));
+ if (old_elements != initial_space_) {
+ delete [] old_elements;
+ }
+}
+
+// -------------------------------------------------------------------
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField()
+ : prototype_(NULL),
+ elements_(initial_space_),
+ current_size_(0),
+ allocated_size_(0),
+ total_size_(kInitialSize) {
+}
+
+template <>
+inline RepeatedPtrField<Message>::RepeatedPtrField(const Message* prototype)
+ : prototype_(prototype),
+ elements_(initial_space_),
+ current_size_(0),
+ allocated_size_(0),
+ total_size_(kInitialSize) {
+}
+
+template <typename Element>
+RepeatedPtrField<Element>::~RepeatedPtrField() {
+ for (int i = 0; i < allocated_size_; i++) {
+ delete elements_[i];
+ }
+ if (elements_ != initial_space_) {
+ delete [] elements_;
+ }
+}
+
+template <>
+inline const Message* RepeatedPtrField<Message>::prototype() const {
+ return prototype_;
+}
+
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::size() const {
+ return current_size_;
+}
+
+
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::Get(int index) const {
+ GOOGLE_DCHECK_LT(index, size());
+ return *elements_[index];
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Mutable(int index) {
+ GOOGLE_DCHECK_LT(index, size());
+ return elements_[index];
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Add() {
+ if (current_size_ < allocated_size_) return elements_[current_size_++];
+ if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
+ ++allocated_size_;
+ return elements_[current_size_++] = NewElement();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::RemoveLast() {
+ GOOGLE_DCHECK_GT(current_size_, 0);
+ elements_[--current_size_]->Clear();
+}
+
+template <>
+inline void RepeatedPtrField<string>::RemoveLast() {
+ GOOGLE_DCHECK_GT(current_size_, 0);
+ elements_[--current_size_]->clear();
+}
+
+template <typename Element>
+void RepeatedPtrField<Element>::Clear() {
+ for (int i = 0; i < current_size_; i++) {
+ elements_[i]->Clear();
+ }
+ current_size_ = 0;
+}
+
+// Specialization defined in repeated_field.cc.
+template <>
+void LIBPROTOBUF_EXPORT RepeatedPtrField<string>::Clear();
+
+template <typename Element>
+void RepeatedPtrField<Element>::MergeFrom(const RepeatedPtrField& other) {
+ Reserve(current_size_ + other.current_size_);
+ for (int i = 0; i < other.current_size_; i++) {
+ Add()->MergeFrom(other.Get(i));
+ }
+}
+
+template <>
+inline void RepeatedPtrField<string>::MergeFrom(const RepeatedPtrField& other) {
+ Reserve(current_size_ + other.current_size_);
+ for (int i = 0; i < other.current_size_; i++) {
+ Add()->assign(other.Get(i));
+ }
+}
+
+
+template <typename Element>
+inline Element** RepeatedPtrField<Element>::mutable_data() {
+ return elements_;
+}
+
+template <typename Element>
+inline const Element* const* RepeatedPtrField<Element>::data() const {
+ return elements_;
+}
+
+
+template <typename Element>
+void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
+ Element** swap_elements = elements_;
+ int swap_current_size = current_size_;
+ int swap_allocated_size = allocated_size_;
+ int swap_total_size = total_size_;
+ // We may not be using initial_space_ but it's not worth checking. Just
+ // copy it anyway.
+ Element* swap_initial_space[kInitialSize];
+ memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
+
+ elements_ = other->elements_;
+ current_size_ = other->current_size_;
+ allocated_size_ = other->allocated_size_;
+ total_size_ = other->total_size_;
+ memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
+
+ other->elements_ = swap_elements;
+ other->current_size_ = swap_current_size;
+ other->allocated_size_ = swap_allocated_size;
+ other->total_size_ = swap_total_size;
+ memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
+
+ if (elements_ == other->initial_space_) {
+ elements_ = initial_space_;
+ }
+ if (other->elements_ == initial_space_) {
+ other->elements_ = other->initial_space_;
+ }
+}
+
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddAllocated(Element* value) {
+ if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
+ // We don't care about the order of cleared elements, so if there's one
+ // in the way, just move it to the back of the array.
+ if (current_size_ < allocated_size_) {
+ elements_[allocated_size_] = elements_[current_size_];
+ }
+ ++allocated_size_;
+ elements_[current_size_++] = value;
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseLast() {
+ GOOGLE_DCHECK_GT(current_size_, 0);
+ Element* result = elements_[--current_size_];
+ --allocated_size_;
+ if (current_size_ < allocated_size_) {
+ // There are cleared elements on the end; replace the removed element
+ // with the last allocated element.
+ elements_[current_size_] = elements_[allocated_size_];
+ }
+ return result;
+}
+
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::ClearedCount() {
+ return allocated_size_ - current_size_;
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddCleared(Element* value) {
+ if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
+ elements_[allocated_size_++] = value;
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseCleared() {
+ GOOGLE_DCHECK_GT(allocated_size_, current_size_);
+ return elements_[--allocated_size_];
+}
+
+
+template <typename Element>
+const void* RepeatedPtrField<Element>::GenericGet(int index) const {
+ return &Get(index);
+}
+
+template <typename Element>
+void* RepeatedPtrField<Element>::GenericMutable(int index) {
+ return Mutable(index);
+}
+
+template <typename Element>
+void* RepeatedPtrField<Element>::GenericAdd() {
+ return Add();
+}
+
+template <typename Element>
+void RepeatedPtrField<Element>::GenericClear() {
+ Clear();
+}
+
+template <typename Element>
+int RepeatedPtrField<Element>::GenericSize() const {
+ return size();
+}
+
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Reserve(int new_size) {
+ if (total_size_ >= new_size) return;
+
+ Element** old_elements = elements_;
+ total_size_ = max(total_size_ * 2, new_size);
+ elements_ = new Element*[total_size_];
+ memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
+ if (old_elements != initial_space_) {
+ delete [] old_elements;
+ }
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::NewElement() {
+ return new Element;
+}
+
+// RepeatedPtrField<Message> is alowed but requires a prototype since Message
+// is abstract.
+template <>
+inline Message* RepeatedPtrField<Message>::NewElement() {
+ return prototype_->New();
+}
+
+// -------------------------------------------------------------------
+
+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<> in util/gtl/iterator_adaptors-inl.h,
+// but adds random-access operators and is slightly more specialized
+// for using T** as its base type. I didn't re-use the other class to
+// avoid an extra dependency.
+//
+// This code stolen from net/proto/proto-array-internal.h by Jeffrey Yasskin
+// (jyasskin@google.com).
+template<typename It>
+class RepeatedPtrIterator
+ : public std::iterator<
+ std::random_access_iterator_tag,
+ typename internal::remove_pointer<
+ typename internal::remove_pointer<It>::type>::type> {
+ public:
+ typedef RepeatedPtrIterator<It> iterator;
+ typedef typename iterator::reference reference;
+ typedef typename iterator::pointer pointer;
+ typedef typename iterator::difference_type difference_type;
+
+ RepeatedPtrIterator() : it_(NULL) {}
+ explicit RepeatedPtrIterator(const It& it) : it_(it) {}
+
+ // Allow "upcasting" from RepeatedPtrIterator<T**> to
+ // RepeatedPtrIterator<const T*const*>.
+ template<typename OtherIt>
+ RepeatedPtrIterator(const RepeatedPtrIterator<OtherIt>& other)
+ : it_(other.base()) {}
+
+ // Provide access to the wrapped iterator.
+ const It& base() const { return it_; }
+
+ // dereferenceable
+ reference operator*() const { return **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
+ bool operator==(const iterator& x) const { return it_ == x.it_; }
+ bool operator!=(const iterator& x) const { return it_ != x.it_; }
+
+ // less_than_comparable
+ bool operator<(const iterator& x) const { return it_ < x.it_; }
+ bool operator<=(const iterator& x) const { return it_ <= x.it_; }
+ bool operator>(const iterator& x) const { return it_ > x.it_; }
+ bool operator>=(const iterator& x) const { return it_ >= x.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
+ difference_type operator-(const iterator& x) const { return it_ - x.it_; }
+
+ private:
+ // The internal iterator.
+ It it_;
+};
+
+} // namespace internal
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::begin() {
+ return iterator(elements_);
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::begin() const {
+ return iterator(elements_);
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::end() {
+ return iterator(elements_ + current_size_);
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::end() const {
+ return iterator(elements_ + current_size_);
+}
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_REPEATED_FIELD_H__
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
new file mode 100644
index 00000000..eb9b096f
--- /dev/null
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -0,0 +1,603 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <algorithm>
+
+#include <google/protobuf/repeated_field.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+// Test operations on a RepeatedField which is small enough that it does
+// not allocate a separate array for storage.
+TEST(RepeatedField, Small) {
+ RepeatedField<int> field;
+
+ EXPECT_EQ(field.size(), 0);
+
+ field.Add(5);
+
+ EXPECT_EQ(field.size(), 1);
+ EXPECT_EQ(field.Get(0), 5);
+
+ field.Add(42);
+
+ EXPECT_EQ(field.size(), 2);
+ EXPECT_EQ(field.Get(0), 5);
+ EXPECT_EQ(field.Get(1), 42);
+
+ field.Set(1, 23);
+
+ EXPECT_EQ(field.size(), 2);
+ EXPECT_EQ(field.Get(0), 5);
+ EXPECT_EQ(field.Get(1), 23);
+
+ field.RemoveLast();
+
+ EXPECT_EQ(field.size(), 1);
+ EXPECT_EQ(field.Get(0), 5);
+
+ field.Clear();
+
+ EXPECT_EQ(field.size(), 0);
+}
+
+// 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_EQ(field.size(), 16);
+
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(field.Get(i), i * i);
+ }
+}
+
+// Test swapping between various types of RepeatedFields.
+TEST(RepeatedField, SwapSmallSmall) {
+ RepeatedField<int> field1;
+ RepeatedField<int> field2;
+
+ field1.Add(5);
+ field1.Add(42);
+
+ field1.Swap(&field2);
+
+ EXPECT_EQ(field1.size(), 0);
+ 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_EQ(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);
+ field.Reserve(30);
+
+ EXPECT_EQ(40, 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_EQ(20, ReservedSpace(&field));
+}
+
+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, 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));
+}
+
+// ===================================================================
+// RepeatedPtrField tests. These pretty much just mirror the RepeatedField
+// tests above.
+
+TEST(RepeatedPtrField, Small) {
+ RepeatedPtrField<string> field;
+
+ EXPECT_EQ(field.size(), 0);
+
+ field.Add()->assign("foo");
+
+ EXPECT_EQ(field.size(), 1);
+ EXPECT_EQ(field.Get(0), "foo");
+
+ field.Add()->assign("bar");
+
+ EXPECT_EQ(field.size(), 2);
+ EXPECT_EQ(field.Get(0), "foo");
+ EXPECT_EQ(field.Get(1), "bar");
+
+ field.Mutable(1)->assign("baz");
+
+ EXPECT_EQ(field.size(), 2);
+ EXPECT_EQ(field.Get(0), "foo");
+ EXPECT_EQ(field.Get(1), "baz");
+
+ field.RemoveLast();
+
+ EXPECT_EQ(field.size(), 1);
+ EXPECT_EQ(field.Get(0), "foo");
+
+ field.Clear();
+
+ EXPECT_EQ(field.size(), 0);
+}
+
+TEST(RepeatedPtrField, Large) {
+ RepeatedPtrField<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);
+ }
+}
+
+TEST(RepeatedPtrField, SwapSmallSmall) {
+ RepeatedPtrField<string> field1;
+ RepeatedPtrField<string> field2;
+
+ field1.Add()->assign("foo");
+ field1.Add()->assign("bar");
+ field1.Swap(&field2);
+
+ 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<string> field1;
+ RepeatedPtrField<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<string> field1;
+ RepeatedPtrField<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<string>* field) {
+ const string* const* ptr = field->data();
+ do {
+ field->Add();
+ } while (field->data() == ptr);
+
+ return field->size() - 1;
+}
+
+TEST(RepeatedPtrField, ReserveMoreThanDouble) {
+ RepeatedPtrField<string> field;
+ field.Reserve(20);
+
+ EXPECT_EQ(20, ReservedSpace(&field));
+}
+
+TEST(RepeatedPtrField, ReserveLessThanDouble) {
+ RepeatedPtrField<string> field;
+ field.Reserve(20);
+ field.Reserve(30);
+
+ EXPECT_EQ(40, ReservedSpace(&field));
+}
+
+TEST(RepeatedPtrField, ReserveLessThanExisting) {
+ RepeatedPtrField<string> field;
+ field.Reserve(20);
+ const string* const* previous_ptr = field.data();
+ field.Reserve(10);
+
+ EXPECT_EQ(previous_ptr, field.data());
+ EXPECT_EQ(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<string> field;
+ 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<string> field;
+
+ 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.ReleaseLast(), 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.AddAllocated(original); // Give ownership back.
+ EXPECT_EQ(field.ClearedCount(), 0);
+ EXPECT_EQ(field.Mutable(1), original);
+
+ field.Clear();
+ EXPECT_EQ(field.ClearedCount(), 2);
+ 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);
+}
+
+TEST(RepeatedPtrField, MergeFrom) {
+ RepeatedPtrField<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, MutableDataIsMutable) {
+ RepeatedPtrField<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.
+ string** data = field.mutable_data();
+ **data = "2";
+ EXPECT_EQ("2", field.Get(0));
+}
+
+// ===================================================================
+
+// Iterator tests stolen from net/proto/proto-array_unittest.
+class RepeatedFieldIteratorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ 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;
+ EXPECT_EQ(0, *c_iter);
+}
+
+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(proto_array_.end() == iter);
+ EXPECT_EQ(2, *(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:
+ virtual void SetUp() {
+ proto_array_.Add()->assign("foo");
+ proto_array_.Add()->assign("bar");
+ proto_array_.Add()->assign("baz");
+ }
+
+ RepeatedPtrField<string> proto_array_;
+};
+
+TEST_F(RepeatedPtrFieldIteratorTest, Convertible) {
+ RepeatedPtrField<string>::iterator iter = proto_array_.begin();
+ RepeatedPtrField<string>::const_iterator c_iter = iter;
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, MutableIteration) {
+ RepeatedPtrField<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<string>& const_proto_array = proto_array_;
+ RepeatedPtrField<string>::const_iterator iter = const_proto_array.begin();
+ 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, RandomAccess) {
+ RepeatedPtrField<string>::iterator iter = proto_array_.begin();
+ RepeatedPtrField<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, Comparable) {
+ RepeatedPtrField<string>::const_iterator iter = proto_array_.begin();
+ RepeatedPtrField<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);
+}
+
+// Uninitialized iterator does not point to any of the RepeatedPtrField.
+// Dereferencing an uninitialized iterator crashes the process.
+TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) {
+ RepeatedPtrField<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());
+#ifdef GTEST_HAS_DEATH_TEST
+ ASSERT_DEATH(GOOGLE_LOG(INFO) << *iter, "");
+#endif
+}
+
+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");
+
+ string v = "f";
+ RepeatedPtrField<string>::const_iterator it =
+ 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<string>::iterator iter = proto_array_.begin();
+ *iter = "qux";
+ EXPECT_EQ("qux", proto_array_.Get(0));
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/service.cc b/src/google/protobuf/service.cc
new file mode 100644
index 00000000..0c997930
--- /dev/null
+++ b/src/google/protobuf/service.cc
@@ -0,0 +1,32 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 00000000..f3e78e7b
--- /dev/null
+++ b/src/google/protobuf/service.h
@@ -0,0 +1,273 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This module declares the abstract interfaces underlying proto2 RPC
+// services. These are intented to be independent of any particular RPC
+// implementation, so that proto2 services can be used on top of a variety
+// of implementations.
+//
+//
+// 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 hypothentical "MyRpcChannel" as an example:
+// MyRpcChannel channel("rpc:hostname:1234/myservice");
+// MyRpcController controller;
+// MyServiceImpl::Stub stub(&channel);
+// FooRequest request;
+// FooRespnose 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/common.h>
+
+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 Message::Reflection).
+class LIBPROTOBUF_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 LIBPROTOBUF_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 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 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 LIBPROTOBUF_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
+#endif // GOOGLE_PROTOBUF_SERVICE_H__
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
new file mode 100644
index 00000000..d7182841
--- /dev/null
+++ b/src/google/protobuf/stubs/common.cc
@@ -0,0 +1,261 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "config.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN // We only need minimal includes
+#include <windows.h>
+#elif defined(HAVE_PTHREAD)
+#include <pthread.h>
+#else
+#error "No suitable threading library available."
+#endif
+
+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 << "\".)";
+ }
+}
+
+string VersionString(int version) {
+ int major = version / 1000000;
+ int minor = (version / 1000) % 1000;
+ int micro = version % 1000;
+
+ return strings::Substitute("$0.$1.$2", major, minor, micro);
+}
+
+} // namespace internal
+
+// ===================================================================
+// emulates google3/base/logging.cc
+
+namespace internal {
+
+void DefaultLogHandler(LogLevel level, const char* filename, int line,
+ const string& message) {
+ 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.
+}
+
+void NullLogHandler(LogLevel level, const char* filename, int line,
+ const string& message) {
+ // Nothing.
+}
+
+static LogHandler* log_handler_ = &DefaultLogHandler;
+static int log_silencer_count_ = 0;
+static Mutex log_silencer_count_mutex_;
+
+static string SimpleCtoa(char c) { return string(1, c); }
+
+#undef DECLARE_STREAM_OPERATOR
+#define DECLARE_STREAM_OPERATOR(TYPE, TOSTRING) \
+ LogMessage& LogMessage::operator<<(TYPE value) { \
+ message_ += TOSTRING(value); \
+ return *this; \
+ }
+
+DECLARE_STREAM_OPERATOR(const string&, )
+DECLARE_STREAM_OPERATOR(const char* , )
+DECLARE_STREAM_OPERATOR(char , SimpleCtoa)
+DECLARE_STREAM_OPERATOR(int , SimpleItoa)
+DECLARE_STREAM_OPERATOR(uint , SimpleItoa)
+DECLARE_STREAM_OPERATOR(double , SimpleDtoa)
+#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) {
+ MutexLock lock(&internal::log_silencer_count_mutex_);
+ suppress = internal::log_silencer_count_ > 0;
+ }
+
+ if (!suppress) {
+ internal::log_handler_(level_, filename_, line_, message_);
+ }
+
+ if (level_ == LOGLEVEL_FATAL) {
+ abort();
+ }
+}
+
+void LogFinisher::operator=(LogMessage& other) {
+ other.Finish();
+}
+
+} // namespace internal
+
+LogHandler* SetLogHandler(LogHandler* new_func) {
+ LogHandler* old = internal::log_handler_;
+ if (old == &internal::NullLogHandler) {
+ old = NULL;
+ }
+ if (new_func == NULL) {
+ internal::log_handler_ = &internal::NullLogHandler;
+ } else {
+ internal::log_handler_ = new_func;
+ }
+ return old;
+}
+
+LogSilencer::LogSilencer() {
+ MutexLock lock(&internal::log_silencer_count_mutex_);
+ ++internal::log_silencer_count_;
+};
+
+LogSilencer::~LogSilencer() {
+ MutexLock lock(&internal::log_silencer_count_mutex_);
+ --internal::log_silencer_count_;
+};
+
+// ===================================================================
+// emulates google3/base/callback.cc
+
+Closure::~Closure() {}
+
+namespace internal { FunctionClosure0::~FunctionClosure0() {} }
+
+void DoNothing() {}
+
+// ===================================================================
+// emulates google3/base/mutex.cc
+
+#ifdef _WIN32
+
+struct Mutex::Internal {
+ CRITICAL_SECTION mutex;
+#ifndef NDEBUG
+ // Used only to implement AssertHeld().
+ DWORD thread_id;
+#endif
+};
+
+Mutex::Mutex()
+ : mInternal(new Internal) {
+ InitializeCriticalSection(&mInternal->mutex);
+}
+
+Mutex::~Mutex() {
+ DeleteCriticalSection(&mInternal->mutex);
+ delete mInternal;
+}
+
+void Mutex::Lock() {
+ EnterCriticalSection(&mInternal->mutex);
+#ifndef NDEBUG
+ mInternal->thread_id = GetCurrentThreadId();
+#endif
+}
+
+void Mutex::Unlock() {
+#ifndef NDEBUG
+ mInternal->thread_id = 0;
+#endif
+ LeaveCriticalSection(&mInternal->mutex);
+}
+
+void Mutex::AssertHeld() {
+#ifndef NDEBUG
+ GOOGLE_DCHECK_EQ(mInternal->thread_id, GetCurrentThreadId());
+#endif
+}
+
+#elif defined(HAVE_PTHREAD)
+
+struct Mutex::Internal {
+ pthread_mutex_t mutex;
+};
+
+Mutex::Mutex()
+ : mInternal(new Internal) {
+ pthread_mutex_init(&mInternal->mutex, NULL);
+}
+
+Mutex::~Mutex() {
+ pthread_mutex_destroy(&mInternal->mutex);
+ delete mInternal;
+}
+
+void Mutex::Lock() {
+ int result = pthread_mutex_lock(&mInternal->mutex);
+ if (result != 0) {
+ GOOGLE_LOG(FATAL) << "pthread_mutex_lock: " << strerror(result);
+ }
+}
+
+void Mutex::Unlock() {
+ int result = pthread_mutex_unlock(&mInternal->mutex);
+ if (result != 0) {
+ GOOGLE_LOG(FATAL) << "pthread_mutex_unlock: " << strerror(result);
+ }
+}
+
+void Mutex::AssertHeld() {
+ // pthreads dosn't provide a way to check which thread holds the mutex.
+ // TODO(kenton): Maybe keep track of locking thread ID like with WIN32?
+}
+
+#endif
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
new file mode 100644
index 00000000..03b176a3
--- /dev/null
+++ b/src/google/protobuf/stubs/common.h
@@ -0,0 +1,1061 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <assert.h>
+#include <stdlib.h>
+#include <cstddef>
+#include <string>
+#include <string.h>
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+
+namespace std {}
+
+namespace google {
+namespace protobuf {
+
+using namespace std; // Don't do this at home, kids.
+
+#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
+#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#ifdef _MSC_VER
+ #ifdef LIBPROTOBUF_EXPORTS
+ #define LIBPROTOBUF_EXPORT __declspec(dllexport)
+ #else
+ #define LIBPROTOBUF_EXPORT __declspec(dllimport)
+ #endif
+ #ifdef LIBPROTOC_EXPORTS
+ #define LIBPROTOC_EXPORT __declspec(dllexport)
+ #else
+ #define LIBPROTOC_EXPORT __declspec(dllimport)
+ #endif
+#else
+ #define LIBPROTOBUF_EXPORT
+ #define LIBPROTOC_EXPORT
+#endif
+
+namespace internal {
+
+// Some of these constants are macros rather than const ints so that they can
+// 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 2000001
+
+// The minimum library version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2000000
+
+// 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 = 2000000;
+
+// The minimum protoc version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2000000
+
+// The minimum header version which works with the current version of
+// protoc. This constant should only be used in VerifyVersion().
+static const int kMinHeaderVersionForProtoc = 2000000;
+
+// Verifies that the headers and libraries are compatible. Use the macro
+// below to call this.
+void LIBPROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion,
+ const char* filename);
+
+// Converts a numeric version number to a string.
+string LIBPROTOBUF_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/base/port.h
+
+typedef unsigned int uint;
+
+#ifdef _MSC_VER
+typedef __int8 int8;
+typedef __int16 int16;
+typedef __int32 int32;
+typedef __int64 int64;
+
+typedef unsigned __int8 uint8;
+typedef unsigned __int16 uint16;
+typedef unsigned __int32 uint32;
+typedef unsigned __int64 uint64;
+#else
+typedef int8_t int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
+
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+#endif
+
+// long long macros to be used because gcc and vc++ use different suffixes,
+// and different size specifiers in format strings
+#undef GOOGLE_LONGLONG
+#undef GOOGLE_ULONGLONG
+#undef GOOGLE_LL_FORMAT
+
+#ifdef _MSC_VER
+#define GOOGLE_LONGLONG(x) x##I64
+#define GOOGLE_ULONGLONG(x) x##UI64
+#define GOOGLE_LL_FORMAT "I64" // As in printf("%I64d", ...)
+#else
+#define GOOGLE_LONGLONG(x) x##LL
+#define GOOGLE_ULONGLONG(x) x##ULL
+#define GOOGLE_LL_FORMAT "ll" // As in "%lld". Note that "q" is poor form also.
+#endif
+
+static const int32 kint32max = 0x7FFFFFFF;
+static const int32 kint32min = -kint32min - 1;
+static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF);
+static const int64 kint64min = -kint64max - 1;
+static const uint32 kuint32max = 0xFFFFFFFFu;
+static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
+
+#undef GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+// For functions we want to force inline.
+// Introduced in gcc 3.1.
+#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
+#else
+// Other compilers will have to figure it out for themselves.
+#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+// ===================================================================
+// from google3/base/basictypes.h
+
+// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.
+//
+// GOOGLE_ARRAYSIZE catches a few type errors. If you see a compiler error
+//
+// "warning: division by zero in ..."
+//
+// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
+// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element). If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array. Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size. Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+//
+// Kudos to Jorg Brown for this simple and elegant implementation.
+
+#undef GOOGLE_ARRAYSIZE
+#define GOOGLE_ARRAYSIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / \
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+namespace internal {
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertable to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+// implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+ return f;
+}
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From> // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) { // so we only accept pointers
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+ if (false) {
+ implicit_cast<From*, To>(0);
+ }
+
+ assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
+ return static_cast<To>(f);
+}
+
+} // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::implicit_cast;
+using internal::down_cast;
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+namespace internal {
+
+template <bool>
+struct CompileAssert {
+};
+
+} // namespace internal
+
+#undef GOOGLE_COMPILE_ASSERT
+#define GOOGLE_COMPILE_ASSERT(expr, msg) \
+ typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \
+ msg[bool(expr) ? 1 : -1]
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// COMPILE_ASSERT(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// ===================================================================
+// from google3/base/scoped_ptr.h
+
+namespace internal {
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class, and its closely-related brethren,
+// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
+
+template <class C> class scoped_ptr;
+template <class C> class scoped_array;
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+//
+// The size of a scoped_ptr is small:
+// sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_ptr.
+ // The input parameter must be allocated with new.
+ explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_ptr() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != ptr_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ ptr_ = p;
+ }
+ }
+
+ // Accessors to get the owned object.
+ // operator* and operator-> will assert() if there is no current object.
+ C& operator*() const {
+ assert(ptr_ != NULL);
+ return *ptr_;
+ }
+ C* operator->() const {
+ assert(ptr_ != NULL);
+ return ptr_;
+ }
+ C* get() const { return ptr_; }
+
+ // Comparison operators.
+ // These return whether two scoped_ptr refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(C* p) const { return ptr_ == p; }
+ bool operator!=(C* p) const { return ptr_ != p; }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr& p2) {
+ C* tmp = ptr_;
+ ptr_ = p2.ptr_;
+ p2.ptr_ = tmp;
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = ptr_;
+ ptr_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* ptr_;
+
+ // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
+ // make sense, and if C2 == C, it still doesn't make sense because you should
+ // never have the same object owned by two different scoped_ptrs.
+ template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_ptr(const scoped_ptr&);
+ void operator=(const scoped_ptr&);
+};
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL. A scoped_array<C> owns the object that it points to.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_array.
+ // The input parameter must be allocated with new [].
+ explicit scoped_array(C* p = NULL) : array_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_array() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != array_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ array_ = p;
+ }
+ }
+
+ // Get one element of the current object.
+ // Will assert() if there is no current object, or index i is negative.
+ C& operator[](std::ptrdiff_t i) const {
+ assert(i >= 0);
+ assert(array_ != NULL);
+ return array_[i];
+ }
+
+ // Get a pointer to the zeroth element of the current object.
+ // If there is no current object, return NULL.
+ C* get() const {
+ return array_;
+ }
+
+ // Comparison operators.
+ // These return whether two scoped_array refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(C* p) const { return array_ == p; }
+ bool operator!=(C* p) const { return array_ != p; }
+
+ // Swap two scoped arrays.
+ void swap(scoped_array& p2) {
+ C* tmp = array_;
+ array_ = p2.array_;
+ p2.array_ = tmp;
+ }
+
+ // Release an array.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = array_;
+ array_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* array_;
+
+ // Forbid comparison of different scoped_array types.
+ template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_array(const scoped_array&);
+ void operator=(const scoped_array&);
+};
+
+} // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::scoped_ptr;
+using internal::scoped_array;
+
+// ===================================================================
+// emulates google3/base/logging.h
+
+enum LogLevel {
+ LOGLEVEL_INFO, // Informational. This is never actually used by
+ // libprotobuf.
+ LOGLEVEL_WARNING, // Warns about issues that, although not technically a
+ // problem now, could cause problems in the future. For
+ // example, a // warning will be printed when parsing a
+ // message that is near the message size limit.
+ LOGLEVEL_ERROR, // An error occurred which should never happen during
+ // normal use.
+ LOGLEVEL_FATAL, // An error occurred from which the library cannot
+ // recover. This usually indicates a programming error
+ // in the code which calls the library, especially when
+ // compiled in debug mode.
+
+#ifdef NDEBUG
+ LOGLEVEL_DFATAL = LOGLEVEL_ERROR
+#else
+ LOGLEVEL_DFATAL = LOGLEVEL_FATAL
+#endif
+};
+
+namespace internal {
+
+class LogFinisher;
+
+class LIBPROTOBUF_EXPORT LogMessage {
+ public:
+ LogMessage(LogLevel level, const char* filename, int line);
+ ~LogMessage();
+
+ LogMessage& operator<<(const string& value);
+ LogMessage& operator<<(const char* value);
+ LogMessage& operator<<(char value);
+ LogMessage& operator<<(int value);
+ LogMessage& operator<<(uint value);
+ LogMessage& operator<<(double value);
+
+ private:
+ friend class LogFinisher;
+ void Finish();
+
+ LogLevel level_;
+ const char* filename_;
+ int line_;
+ string message_;
+};
+
+// Used to make the entire "LOG(BLAH) << etc." expression have a void return
+// type and print a newline after each message.
+class LIBPROTOBUF_EXPORT LogFinisher {
+ public:
+ void operator=(LogMessage& other);
+};
+
+} // namespace internal
+
+// Undef everything in case we're being mixed with some other Google library
+// which already defined them itself. Presumably all Google libraries will
+// support the same syntax for these so it should not be a big deal if they
+// end up using our definitions instead.
+#undef GOOGLE_LOG
+#undef GOOGLE_LOG_IF
+
+#undef GOOGLE_CHECK
+#undef GOOGLE_CHECK_EQ
+#undef GOOGLE_CHECK_NE
+#undef GOOGLE_CHECK_LT
+#undef GOOGLE_CHECK_LE
+#undef GOOGLE_CHECK_GT
+#undef GOOGLE_CHECK_GE
+
+#undef GOOGLE_DLOG
+#undef GOOGLE_DCHECK
+#undef GOOGLE_DCHECK_EQ
+#undef GOOGLE_DCHECK_NE
+#undef GOOGLE_DCHECK_LT
+#undef GOOGLE_DCHECK_LE
+#undef GOOGLE_DCHECK_GT
+#undef GOOGLE_DCHECK_GE
+
+#define GOOGLE_LOG(LEVEL) \
+ ::google::protobuf::internal::LogFinisher() = \
+ ::google::protobuf::internal::LogMessage( \
+ ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
+#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
+ !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
+
+#define GOOGLE_CHECK(EXPRESSION) \
+ GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
+#define GOOGLE_CHECK_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)
+
+#ifdef NDEBUG
+
+#define GOOGLE_DLOG GOOGLE_LOG_IF(false, INFO)
+
+#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
+#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK(A == B)
+#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK(A != B)
+#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK(A < B)
+#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK(A <= B)
+#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK(A > B)
+#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK(A >= B)
+
+#else // NDEBUG
+
+#define GOOGLE_DLOG GOOGLE_LOG
+
+#define GOOGLE_DCHECK GOOGLE_CHECK
+#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
+#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
+#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
+#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
+#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
+#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
+
+#endif // !NDEBUG
+
+typedef void LogHandler(LogLevel level, const char* filename, int line,
+ const string& message);
+
+// The protobuf library sometimes writes warning and error messages to
+// stderr. These messages are primarily useful for developers, but may
+// also help end users figure out a problem. If you would prefer that
+// these messages be sent somewhere other than stderr, call SetLogHandler()
+// to set your own handler. This returns the old handler. Set the handler
+// to NULL to ignore log messages (but see also LogSilencer, below).
+//
+// Obviously, SetLogHandler is not thread-safe. You should only call it
+// at initialization time, and probably not from library code. If you
+// simply want to suppress log messages temporarily (e.g. because you
+// have some code that tends to trigger them frequently and you know
+// the warnings are not important to you), use the LogSilencer class
+// below.
+LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
+
+// Create a LogSilencer if you want to temporarily suppress all log
+// messages. As long as any LogSilencer objects exist, non-fatal
+// log messages will be discarded (the current LogHandler will *not*
+// be called). Constructing a LogSilencer is thread-safe. You may
+// accidentally suppress log messages occurring in another thread, but
+// since messages are generally for debugging purposes only, this isn't
+// a big deal. If you want to intercept log messages, use SetLogHandler().
+class LIBPROTOBUF_EXPORT LogSilencer {
+ public:
+ LogSilencer();
+ ~LogSilencer();
+};
+
+// ===================================================================
+// emulates google3/base/callback.h
+
+// Abstract interface for a callback. When calling an RPC, you must provide
+// a Closure to call when the procedure completes. See the Service interface
+// in service.h.
+//
+// To automatically construct a Closure which calls a particular function or
+// method with a particular set of parameters, use the NewCallback() function.
+// Example:
+// void FooDone(const FooResponse* response) {
+// ...
+// }
+//
+// void CallFoo() {
+// ...
+// // When done, call FooDone() and pass it a pointer to the response.
+// Closure* callback = NewCallback(&FooDone, response);
+// // Make the call.
+// service->Foo(controller, request, response, callback);
+// }
+//
+// Example that calls a method:
+// class Handler {
+// public:
+// ...
+//
+// void FooDone(const FooResponse* response) {
+// ...
+// }
+//
+// void CallFoo() {
+// ...
+// // When done, call FooDone() and pass it a pointer to the response.
+// Closure* callback = NewCallback(this, &Handler::FooDone, response);
+// // Make the call.
+// service->Foo(controller, request, response, callback);
+// }
+// };
+//
+// Currently NewCallback() supports binding zero, one, or two arguments.
+//
+// Callbacks created with NewCallback() automatically delete themselves when
+// executed. They should be used when a callback is to be called exactly
+// once (usually the case with RPC callbacks). If a callback may be called
+// a different number of times (including zero), create it with
+// NewPermanentCallback() instead. You are then responsible for deleting the
+// callback (using the "delete" keyword as normal).
+//
+// Note that NewCallback() is a bit touchy regarding argument types. Generally,
+// the values you provide for the parameter bindings must exactly match the
+// types accepted by the callback function. For example:
+// void Foo(string s);
+// NewCallback(&Foo, "foo"); // WON'T WORK: const char* != string
+// NewCallback(&Foo, string("foo")); // WORKS
+// Also note that the arguments cannot be references:
+// void Foo(const string& s);
+// string my_str;
+// NewCallback(&Foo, my_str); // WON'T WORK: Can't use referecnes.
+// However, correctly-typed pointers will work just fine.
+class LIBPROTOBUF_EXPORT Closure {
+ public:
+ Closure() {}
+ virtual ~Closure();
+
+ virtual void Run() = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
+};
+
+namespace internal {
+
+class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure {
+ public:
+ typedef void (*FunctionType)();
+
+ FunctionClosure0(FunctionType function, bool self_deleting)
+ : function_(function), self_deleting_(self_deleting) {}
+ ~FunctionClosure0();
+
+ void Run() {
+ function_();
+ if (self_deleting_) 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() {
+ (object_->*method_)();
+ if (self_deleting_) 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() {
+ function_(arg1_);
+ if (self_deleting_) 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() {
+ (object_->*method_)(arg1_);
+ if (self_deleting_) 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() {
+ function_(arg1_, arg2_);
+ if (self_deleting_) 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() {
+ (object_->*method_)(arg1_, arg2_);
+ if (self_deleting_) delete this;
+ }
+
+ private:
+ Class* object_;
+ MethodType method_;
+ bool self_deleting_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+};
+
+} // namespace internal
+
+// See Closure.
+inline Closure* NewCallback(void (*function)()) {
+ return new internal::FunctionClosure0(function, true);
+}
+
+// See Closure.
+inline Closure* NewPermanentCallback(void (*function)()) {
+ return new internal::FunctionClosure0(function, false);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewCallback(Class* object, void (Class::*method)()) {
+ return new internal::MethodClosure0<Class>(object, method, true);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
+ return new internal::MethodClosure0<Class>(object, method, false);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewCallback(void (*function)(Arg1),
+ Arg1 arg1) {
+ return new internal::FunctionClosure1<Arg1>(function, true, arg1);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewPermanentCallback(void (*function)(Arg1),
+ Arg1 arg1) {
+ return new internal::FunctionClosure1<Arg1>(function, false, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
+ Arg1 arg1) {
+ return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
+ Arg1 arg1) {
+ return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewCallback(void (*function)(Arg1, Arg2),
+ Arg1 arg1, Arg2 arg2) {
+ return new internal::FunctionClosure2<Arg1, Arg2>(
+ function, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
+ Arg1 arg1, Arg2 arg2) {
+ return new internal::FunctionClosure2<Arg1, Arg2>(
+ function, false, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
+ Arg1 arg1, Arg2 arg2) {
+ return new internal::MethodClosure2<Class, Arg1, Arg2>(
+ object, method, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(
+ Class* object, void (Class::*method)(Arg1, Arg2),
+ Arg1 arg1, Arg2 arg2) {
+ return new internal::MethodClosure2<Class, Arg1, Arg2>(
+ object, method, false, arg1, arg2);
+}
+
+// A function which does nothing. Useful for creating no-op callbacks, e.g.:
+// Closure* nothing = NewCallback(&DoNothing);
+void LIBPROTOBUF_EXPORT DoNothing();
+
+// ===================================================================
+// emulates google3/base/mutex.h
+
+namespace internal {
+
+// A Mutex is a non-reentrant (aka non-recursive) mutex. At most one thread T
+// may hold a mutex at a given time. If T attempts to Lock() the same Mutex
+// while holding it, T will deadlock.
+class LIBPROTOBUF_EXPORT Mutex {
+ public:
+ // Create a Mutex that is not held by anybody.
+ Mutex();
+
+ // Destructor
+ ~Mutex();
+
+ // Block if necessary until this Mutex is free, then acquire it exclusively.
+ void Lock();
+
+ // Release this Mutex. Caller must hold it exclusively.
+ void Unlock();
+
+ // Crash if this Mutex is not held exclusively by this thread.
+ // May fail to crash when it should; will never crash when it should not.
+ void AssertHeld();
+
+ private:
+ struct Internal;
+ Internal* mInternal;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex);
+};
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class LIBPROTOBUF_EXPORT MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
+ ~MutexLock() { this->mu_->Unlock(); }
+ private:
+ Mutex *const mu_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
+};
+
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
+class LIBPROTOBUF_EXPORT MutexLockMaybe {
+ public:
+ explicit MutexLockMaybe(Mutex *mu) :
+ mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
+ ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } }
+ private:
+ Mutex *const mu_;
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
+};
+
+} // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::Mutex;
+using internal::MutexLock;
+using internal::MutexLockMaybe;
+
+// ===================================================================
+// from google3/base/type_traits.h
+
+namespace internal {
+
+// Specified by TR1 [4.7.4] Pointer modifications.
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T* const> { typedef T type; };
+template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
+template<typename T> struct remove_pointer<T* const volatile> {
+ typedef T type; };
+
+} // namespace internal
+
+} // namespace protobuf
+} // namespace google
+
+#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 00000000..f12422be
--- /dev/null
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -0,0 +1,319 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+#include "config.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", so we remove that.
+ string version = PACKAGE_VERSION;
+ int pos = version.size();
+ while (pos > 0 && !ascii_isdigit(version[pos-1])) {
+ --pos;
+ }
+ version.erase(pos);
+
+ EXPECT_EQ(version, internal::VersionString(GOOGLE_PROTOBUF_VERSION));
+}
+
+#endif // PACKAGE_VERSION
+
+vector<string> captured_messages_;
+
+void CaptureLog(LogLevel level, const char* filename, int line,
+ const 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.";
+
+ 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(NULL);
+
+ CaptureTestStderr();
+ GOOGLE_LOG(INFO ) << "A message.";
+ GOOGLE_LOG(WARNING) << "A warning.";
+ GOOGLE_LOG(ERROR ) << "An error.";
+
+ EXPECT_TRUE(SetLogHandler(old_handler) == NULL);
+
+ 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(string c) { c_ = c; }
+
+ static void SetAFunction(int a) { current_instance_->a_ = a; }
+ static void SetCFunction(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_ = NULL;
+ c_.clear();
+ }
+
+ int a_;
+ const char* b_;
+ string c_;
+
+ static ClosureTest* current_instance_;
+};
+
+ClosureTest* ClosureTest::current_instance_ = NULL;
+
+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, string("test"));
+ EXPECT_NE("test", c_);
+ closure->Run();
+ EXPECT_EQ("test", c_);
+}
+
+TEST_F(ClosureTest, TestClosureMethod1String) {
+ Closure* closure = NewCallback(current_instance_,
+ &ClosureTest::SetCMethod, 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_ = NULL;
+ 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_ = NULL;
+ closure->Run();
+ EXPECT_EQ(789, a_);
+ EXPECT_EQ(cstr, b_);
+ delete closure;
+}
+
+} // anonymous namespace
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/hash.cc b/src/google/protobuf/stubs/hash.cc
new file mode 100644
index 00000000..43fb9d73
--- /dev/null
+++ b/src/google/protobuf/stubs/hash.cc
@@ -0,0 +1,27 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/hash.h>
+
+namespace google {
+namespace protobuf {
+
+// Nothing needed here right now.
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
new file mode 100644
index 00000000..a62b3f6e
--- /dev/null
+++ b/src/google/protobuf/stubs/hash.h
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// Deals with the fact that hash_map is not defined everywhere.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
+#define GOOGLE_PROTOBUF_STUBS_HASH_H__
+
+#include <string.h>
+#include <google/protobuf/stubs/common.h>
+#include "config.h"
+
+#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
+#include HASH_MAP_H
+#include HASH_SET_H
+#else
+// TODO(kenton): Deal with non-existence of hash_map somehow. Maybe emulate
+// it with map?
+#error "Your STL implementation lacks hash_map and/or hash_set."
+#endif
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+
+template <typename Key>
+struct hash : public HASH_NAMESPACE::hash_compare<Key> {
+};
+
+// MSVC's hash_compare<const char*> hashes based on the string contents but
+// compares based on the string pointer. WTF?
+class CstringLess {
+ public:
+ inline bool operator()(const char* a, const char* b) const {
+ return strcmp(a, b) < 0;
+ }
+};
+
+template <>
+struct hash<const char*>
+ : public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
+};
+
+template <typename Key, typename Data,
+ typename HashFcn = hash<Key>,
+ typename EqualKey = int >
+class hash_map : public HASH_NAMESPACE::hash_map<
+ Key, Data, HashFcn> {
+};
+
+template <typename Key,
+ typename HashFcn = hash<Key>,
+ typename EqualKey = int >
+class hash_set : public HASH_NAMESPACE::hash_set<
+ Key, HashFcn> {
+};
+
+#else
+
+template <typename Key>
+struct hash : public HASH_NAMESPACE::hash<Key> {
+};
+
+template <typename Key>
+struct hash<const Key*> {
+ inline size_t operator()(const Key* key) const {
+ return reinterpret_cast<size_t>(key);
+ }
+};
+
+template <>
+struct hash<const char*> : public HASH_NAMESPACE::hash<const char*> {
+};
+
+template <typename Key, typename Data,
+ typename HashFcn = hash<Key>,
+ typename EqualKey = std::equal_to<Key> >
+class hash_map : public HASH_NAMESPACE::hash_map<
+ Key, Data, HashFcn, EqualKey> {
+};
+
+template <typename Key,
+ typename HashFcn = hash<Key>,
+ typename EqualKey = std::equal_to<Key> >
+class hash_set : public HASH_NAMESPACE::hash_set<
+ Key, HashFcn, EqualKey> {
+};
+
+#endif
+
+template <>
+struct hash<string> {
+ inline size_t operator()(const 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 size_t operator()(const string& a, const string& b) const {
+ return a < b;
+ }
+};
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__
diff --git a/src/google/protobuf/stubs/map-util.cc b/src/google/protobuf/stubs/map-util.cc
new file mode 100644
index 00000000..af05af30
--- /dev/null
+++ b/src/google/protobuf/stubs/map-util.cc
@@ -0,0 +1,28 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/util/gtl/map-util.cc
+// Author: Anton Carver
+
+#include <google/protobuf/stubs/map-util.h>
+
+namespace google {
+namespace protobuf {
+
+// Template module. Nothing to see here.
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h
new file mode 100644
index 00000000..ee8073fe
--- /dev/null
+++ b/src/google/protobuf/stubs/map-util.h
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/util/gtl/map-util.h
+// Author: Anton Carver
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// Perform a lookup in a map or hash_map.
+// If the key is present a const pointer to the associated value is returned,
+// otherwise a NULL pointer is returned.
+template <class Collection>
+const typename Collection::value_type::second_type*
+FindOrNull(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ return &it->second;
+}
+
+// Perform a lookup in a map or hash_map whose values are pointers.
+// If the key is present a const pointer to the associated value is returned,
+// otherwise a NULL pointer is returned.
+// This function does not distinguish between a missing key and a key mapped
+// to a NULL value.
+template <class Collection>
+const typename Collection::value_type::second_type
+FindPtrOrNull(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ return it->second;
+}
+
+// Change the value associated with a particular key in a map or hash_map.
+// If the key is not present in the map the key and value are inserted,
+// otherwise the value is updated to be a copy of the value provided.
+// True indicates that an insert took place, false indicates an update.
+template <class Collection, class Key, class Value>
+bool InsertOrUpdate(Collection * const collection,
+ const Key& key, const Value& value) {
+ pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, value));
+ if (!ret.second) {
+ // update
+ ret.first->second = value;
+ return false;
+ }
+ return true;
+}
+
+// Insert a new key and value into a map or hash_map.
+// If the key is not present in the map the key and value are
+// inserted, otherwise nothing happens. True indicates that an insert
+// took place, false indicates the key was already present.
+template <class Collection, class Key, class Value>
+bool InsertIfNotPresent(Collection * const collection,
+ const Key& key, const Value& value) {
+ pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, value));
+ return ret.second;
+}
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/src/google/protobuf/stubs/stl_util-inl.cc b/src/google/protobuf/stubs/stl_util-inl.cc
new file mode 100644
index 00000000..445c646e
--- /dev/null
+++ b/src/google/protobuf/stubs/stl_util-inl.cc
@@ -0,0 +1,27 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/util/gtl/stl_util-inl.cc
+
+#include <google/protobuf/stubs/stl_util-inl.h>
+
+namespace google {
+namespace protobuf {
+
+// Template module. Nothing to see here.
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/stubs/stl_util-inl.h b/src/google/protobuf/stubs/stl_util-inl.h
new file mode 100644
index 00000000..db079a77
--- /dev/null
+++ b/src/google/protobuf/stubs/stl_util-inl.h
@@ -0,0 +1,107 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/util/gtl/stl_util-inl.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
+#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// STLDeleteContainerPointers()
+// For a range within a container of pointers, calls delete
+// (non-array version) on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+// Inside Google, this function implements a horrible, disgusting hack in which
+// we reach into the string's private implementation and resize it without
+// initializing the new bytes. In some cases doing this can significantly
+// improve performance. However, since it's totally non-portable it has no
+// place in open source code. Feel free to fill this function in with your
+// own disgusting hack if you want the perf boost.
+inline void STLStringResizeUninitialized(string* s, size_t new_size) {
+ s->resize(new_size);
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(string* str) {
+ // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+ return str->empty() ? NULL : &*str->begin();
+}
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container. This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// ElementDeleter (defined below), which ensures that your container's elements
+// are deleted when the ElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T *container) {
+ if (!container) return;
+ STLDeleteContainerPointers(container->begin(), container->end());
+ container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container. Does nothing
+// in the case it's given a NULL pointer.
+
+template <class T>
+void STLDeleteValues(T *v) {
+ if (!v) return;
+ for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
+ delete i->second;
+ }
+ v->clear();
+}
+
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
new file mode 100644
index 00000000..07caaf76
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -0,0 +1,1121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/strings/strutil.cc
+
+#include <google/protobuf/stubs/strutil.h>
+#include <errno.h>
+#include <float.h> // FLT_DIG and DBL_DIG
+#include <limits>
+#include <limits.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 {
+
+inline bool IsNaN(double value) {
+ // NaN is never equal to anything, even itself.
+ return value != value;
+}
+
+// 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.
+static bool isxdigit(char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F');
+}
+
+static bool isprint(char c) {
+ return c >= 0x20 && c <= 0x7E;
+}
+
+// ----------------------------------------------------------------------
+// StripString
+// Replaces any occurrence of the character 'remove' (or the characters
+// in 'remove') with the character 'replacewith'.
+// ----------------------------------------------------------------------
+void StripString(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 != NULL;
+ str = strpbrk(str + 1, remove)) {
+ (*s)[str - str_start] = replacewith;
+ }
+}
+
+// ----------------------------------------------------------------------
+// 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 string& s, const string& oldsub,
+ const string& newsub, bool replace_all,
+ string* res) {
+ if (oldsub.empty()) {
+ res->append(s); // if empty, append the given string.
+ return;
+ }
+
+ string::size_type start_pos = 0;
+ string::size_type pos;
+ do {
+ pos = s.find(oldsub, start_pos);
+ if (pos == 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.
+// ----------------------------------------------------------------------
+
+string StringReplace(const string& s, const string& oldsub,
+ const string& newsub, bool replace_all) {
+ 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(const string& 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++ = string(start, p - start);
+ }
+ }
+ return;
+ }
+
+ string::size_type begin_index, end_index;
+ begin_index = full.find_first_not_of(delim);
+ while (begin_index != string::npos) {
+ end_index = full.find_first_of(delim, begin_index);
+ if (end_index == string::npos) {
+ *result++ = full.substr(begin_index);
+ return;
+ }
+ *result++ = full.substr(begin_index, (end_index - begin_index));
+ begin_index = full.find_first_not_of(delim, end_index);
+ }
+}
+
+void SplitStringUsing(const string& full,
+ const char* delim,
+ vector<string>* result) {
+ back_insert_iterator< vector<string> > it(*result);
+ SplitStringToIteratorUsing(full, delim, 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,
+ string* result) {
+ GOOGLE_CHECK(result != NULL);
+ 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 vector<string>& components,
+ const char* delim,
+ 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 NULL, it reports the errors with LOG().
+// ----------------------------------------------------------------------
+
+#define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7'))
+
+inline int hex_digit_to_int(char c) {
+ /* Assume ASCII. */
+ assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61);
+ assert(isxdigit(c));
+ int x = static_cast<unsigned char>(c);
+ if (x > '9') {
+ x += 9;
+ }
+ return x & 0xf;
+}
+
+// Protocol buffers doesn't ever care about errors, but I don't want to remove
+// the code.
+#define LOG_STRING(LEVEL, VECTOR) GOOGLE_LOG_IF(LEVEL, false)
+
+int UnescapeCEscapeSequences(const char* source, char* dest) {
+ return UnescapeCEscapeSequences(source, dest, NULL);
+}
+
+int UnescapeCEscapeSequences(const char* source, char* dest,
+ vector<string> *errors) {
+ GOOGLE_DCHECK(errors == NULL) << "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 " <<
+ "\\" << 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: \\"
+ << 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 \\"
+ << 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: \\"
+ << 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 NULL, 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 string& src, string* dest) {
+ return UnescapeCEscapeString(src, dest, NULL);
+}
+
+int UnescapeCEscapeString(const string& src, string* dest,
+ vector<string> *errors) {
+ scoped_array<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;
+}
+
+string UnescapeCEscapeString(const string& src) {
+ scoped_array<char> unescaped(new char[src.size() + 1]);
+ int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), NULL);
+ return 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.
+// ----------------------------------------------------------------------
+static int CEscapeInternal(const char* src, int src_len, char* dest,
+ int dest_len, bool use_hex) {
+ 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 (!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>(*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;
+}
+
+int CEscapeString(const char* src, int src_len, char* dest, int dest_len) {
+ return CEscapeInternal(src, src_len, dest, dest_len, false);
+}
+
+// ----------------------------------------------------------------------
+// CEscape()
+// CHexEscape()
+// Copies 'src' to result, escaping dangerous characters using
+// C-style escape sequences. This is very useful for preparing query
+// flags. 'src' and 'dest' should not overlap. The 'Hex' version
+// hexadecimal rather than octal sequences.
+//
+// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// ----------------------------------------------------------------------
+string CEscape(const string& src) {
+ const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
+ scoped_array<char> dest(new char[dest_length]);
+ const int len = CEscapeInternal(src.data(), src.size(),
+ dest.get(), dest_length, false);
+ GOOGLE_DCHECK_GE(len, 0);
+ return string(dest.get(), len);
+}
+
+// ----------------------------------------------------------------------
+// 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 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 kint32min;
+ } else if (errno == ERANGE && result == LONG_MAX) {
+ return kint32max;
+ } else if (errno == 0 && result < kint32min) {
+ errno = ERANGE;
+ return kint32min;
+ } else if (errno == 0 && result > kint32max) {
+ errno = ERANGE;
+ return kint32max;
+ }
+ if (errno == 0)
+ errno = saved_errno;
+ return static_cast<int32>(result);
+}
+
+uint32 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 kuint32max;
+ } else if (errno == 0 && result > kuint32max) {
+ errno = ERANGE;
+ return kuint32max;
+ }
+ if (errno == 0)
+ errno = saved_errno;
+ return static_cast<uint32>(result);
+}
+
+// ----------------------------------------------------------------------
+// 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 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 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 value, char* buffer, int num_byte) {
+ static const char *hexdigits = "0123456789abcdef";
+ buffer[num_byte] = '\0';
+ for (int i = num_byte - 1; i >= 0; i--) {
+ buffer[i] = hexdigits[uint32(value) & 0xf];
+ value >>= 4;
+ }
+ return buffer;
+}
+
+char *FastHex64ToBuffer(uint64 value, char* buffer) {
+ return InternalFastHexToBuffer(value, buffer, 16);
+}
+
+char *FastHex32ToBuffer(uint32 value, char* buffer) {
+ return InternalFastHexToBuffer(value, buffer, 8);
+}
+
+static inline char* PlaceNum(char* p, int num, char prev_sep) {
+ *p-- = '0' + num % 10;
+ *p-- = '0' + num / 10;
+ *p-- = prev_sep;
+ return p;
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBufferLeft()
+// FastUInt32ToBufferLeft()
+// 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 u, char* buffer) {
+ int digits;
+ const char *ASCII_digits = NULL;
+ // 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 i, char* buffer) {
+ uint32 u = i;
+ if (i < 0) {
+ *buffer++ = '-';
+ u = -i;
+ }
+ return FastUInt32ToBufferLeft(u, buffer);
+}
+
+char* FastUInt64ToBufferLeft(uint64 u64, char* buffer) {
+ int digits;
+ const char *ASCII_digits = NULL;
+
+ uint32 u = static_cast<uint32>(u64);
+ if (u == u64) return FastUInt32ToBufferLeft(u, buffer);
+
+ uint64 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 i, char* buffer) {
+ uint64 u = i;
+ if (i < 0) {
+ *buffer++ = '-';
+ u = -i;
+ }
+ return FastUInt64ToBufferLeft(u, buffer);
+}
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+// Description: converts an integer to a string.
+//
+// Return value: string
+// ----------------------------------------------------------------------
+
+string SimpleItoa(int i) {
+ char buffer[kFastToBufferSize];
+ return (sizeof(i) == 4) ?
+ FastInt32ToBuffer(i, buffer) :
+ FastInt64ToBuffer(i, buffer);
+}
+
+string SimpleItoa(unsigned int i) {
+ char buffer[kFastToBufferSize];
+ return string(buffer, (sizeof(i) == 4) ?
+ FastUInt32ToBufferLeft(i, buffer) :
+ FastUInt64ToBufferLeft(i, buffer));
+}
+
+string SimpleItoa(long i) {
+ char buffer[kFastToBufferSize];
+ return (sizeof(i) == 4) ?
+ FastInt32ToBuffer(i, buffer) :
+ FastInt64ToBuffer(i, buffer);
+}
+
+string SimpleItoa(unsigned long i) {
+ char buffer[kFastToBufferSize];
+ return string(buffer, (sizeof(i) == 4) ?
+ FastUInt32ToBufferLeft(i, buffer) :
+ FastUInt64ToBufferLeft(i, buffer));
+}
+
+string SimpleItoa(long long i) {
+ char buffer[kFastToBufferSize];
+ return (sizeof(i) == 4) ?
+ FastInt32ToBuffer(i, buffer) :
+ FastInt64ToBuffer(i, buffer);
+}
+
+string SimpleItoa(unsigned long long i) {
+ char buffer[kFastToBufferSize];
+ return 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.
+// ----------------------------------------------------------------------
+
+string SimpleDtoa(double value) {
+ char buffer[kDoubleToBufferSize];
+ return DoubleToBuffer(value, buffer);
+}
+
+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, '.') != NULL) 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.
+ GOOGLE_COMPILE_ASSERT(DBL_DIG < 20, DBL_DIG_is_too_big);
+
+ if (value == numeric_limits<double>::infinity()) {
+ strcpy(buffer, "inf");
+ return buffer;
+ } else if (value == -numeric_limits<double>::infinity()) {
+ strcpy(buffer, "-inf");
+ return buffer;
+ } else if (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 = strtod(buffer, NULL);
+ if (parsed_value != value) {
+ int 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;
+}
+
+bool safe_strtof(const char* str, float* value) {
+ char* endptr;
+ errno = 0; // errno only gets set on errors
+#ifdef _WIN32 // has no strtof()
+ *value = strtod(str, &endptr);
+#else
+ *value = strtof(str, &endptr);
+#endif
+ return *str != 0 && *endptr == 0 && errno == 0;
+}
+
+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.
+ GOOGLE_COMPILE_ASSERT(FLT_DIG < 10, FLT_DIG_is_too_big);
+
+ if (value == numeric_limits<double>::infinity()) {
+ strcpy(buffer, "inf");
+ return buffer;
+ } else if (value == -numeric_limits<double>::infinity()) {
+ strcpy(buffer, "-inf");
+ return buffer;
+ } else if (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) {
+ int snprintf_result =
+ snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
+
+ // Should never overflow; see above.
+ GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
+ }
+
+ DelocalizeRadix(buffer);
+ return buffer;
+}
+
+// ----------------------------------------------------------------------
+// NoLocaleStrtod()
+// This code will make you cry.
+// ----------------------------------------------------------------------
+
+// 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.
+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 = sprintf(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.
+ 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;
+}
+
+double NoLocaleStrtod(const char* text, char** original_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(text, &temp_endptr);
+ if (original_endptr != NULL) *original_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.
+ string localized = LocalizeRadix(text, 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 - text)) {
+ // This attempt got further, so replacing the decimal must have helped.
+ // Update original_endptr to point at the right location.
+ if (original_endptr != NULL) {
+ // size_diff is non-zero if the localized radix has multiple bytes.
+ int size_diff = localized.size() - strlen(text);
+ // const_cast is necessary to match the strtod() interface.
+ *original_endptr = const_cast<char*>(
+ text + (localized_endptr - localized_cstr - size_diff));
+ }
+ }
+
+ return result;
+}
+
+} // 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 00000000..ff919617
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil.h
@@ -0,0 +1,432 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// from google3/strings/strutil.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#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.
+// ----------------------------------------------------------------------
+
+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');
+}
+
+// ----------------------------------------------------------------------
+// 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(const string& str,
+ const string& prefix) {
+ return str.size() >= prefix.size() &&
+ str.compare(0, prefix.size(), prefix) == 0;
+}
+
+inline string StripPrefixString(const string& str, const 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(const string& str,
+ const string& suffix) {
+ return str.size() >= suffix.size() &&
+ str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+inline string StripSuffixString(const string& str, const string& suffix) {
+ if (HasSuffixString(str, suffix)) {
+ return str.substr(0, str.size() - suffix.size());
+ } else {
+ return str;
+ }
+}
+
+// ----------------------------------------------------------------------
+// StripString
+// 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.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove,
+ char replacewith);
+
+// ----------------------------------------------------------------------
+// LowerString()
+// UpperString()
+// 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(string * s) {
+ string::iterator end = s->end();
+ for (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(string * s) {
+ string::iterator end = s->end();
+ for (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';
+ }
+}
+
+// ----------------------------------------------------------------------
+// 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.
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub,
+ const 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.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim,
+ vector<string>* res);
+
+// ----------------------------------------------------------------------
+// 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.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void JoinStrings(const vector<string>& components,
+ const char* delim, string* result);
+
+inline string JoinStrings(const vector<string>& components,
+ const char* delim) {
+ 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). For the inverse
+// transformation, use UniLib::UTF8EscapeString
+// (util/utf8/unilib.h), not CEscapeString.
+//
+// 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 vector is NULL; otherwise, error
+// messages are stored in the vector. In either case, the effect on
+// the dest array is not defined, but rest of the source will be
+// processed.
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
+LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
+ vector<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 NULL, 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.
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest);
+LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest,
+ vector<string> *errors);
+LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
+
+// ----------------------------------------------------------------------
+// CEscapeString()
+// Copies 'src' to 'dest', escaping dangerous characters using
+// C-style escape sequences. This is very useful for preparing query
+// flags. 'src' and 'dest' should not overlap.
+// Returns the number of bytes written to 'dest' (not including the \0)
+// or -1 if there was insufficient space.
+//
+// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len,
+ char* dest, int dest_len);
+
+// ----------------------------------------------------------------------
+// CEscape()
+// More convenient form of CEscapeString: returns result as a "string".
+// This version is slower than CEscapeString() because it does more
+// allocation. However, it is much more convenient to use in
+// non-speed-critical code like logging messages etc.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT string CEscape(const string& src);
+
+// ----------------------------------------------------------------------
+// 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.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int32 strto32_adaptor(const char *nptr, char **endptr,
+ int base);
+LIBPROTOBUF_EXPORT uint32 strtou32_adaptor(const char *nptr, char **endptr,
+ int base);
+
+inline int32 strto32(const char *nptr, char **endptr, int base) {
+ if (sizeof(int32) == sizeof(long))
+ return strtol(nptr, endptr, base);
+ else
+ return strto32_adaptor(nptr, endptr, base);
+}
+
+inline uint32 strtou32(const char *nptr, char **endptr, int base) {
+ if (sizeof(uint32) == 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 strto64(const char *nptr, char **endptr, int base) {
+ GOOGLE_COMPILE_ASSERT(sizeof(int64) == sizeof(long long),
+ sizeof_int64_is_not_sizeof_long_long);
+ return strtoll(nptr, endptr, base);
+}
+
+inline uint64 strtou64(const char *nptr, char **endptr, int base) {
+ GOOGLE_COMPILE_ASSERT(sizeof(uint64) == sizeof(unsigned long long),
+ sizeof_uint64_is_not_sizeof_long_long);
+ return strtoull(nptr, endptr, base);
+}
+
+// ----------------------------------------------------------------------
+// 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;
+
+LIBPROTOBUF_EXPORT char* FastInt32ToBuffer(int32 i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastInt64ToBuffer(int64 i, char* buffer);
+char* FastUInt32ToBuffer(uint32 i, char* buffer); // inline below
+char* FastUInt64ToBuffer(uint64 i, char* buffer); // inline below
+LIBPROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastHex64ToBuffer(uint64 i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastHex32ToBuffer(uint32 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).
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32 i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32 i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64 i, char* buffer);
+LIBPROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64 i, char* buffer);
+
+// Just define these in terms of the above.
+inline char* FastUInt32ToBuffer(uint32 i, char* buffer) {
+ FastUInt32ToBufferLeft(i, buffer);
+ return buffer;
+}
+inline char* FastUInt64ToBuffer(uint64 i, char* buffer) {
+ FastUInt64ToBufferLeft(i, buffer);
+ return buffer;
+}
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+// Description: converts an integer to a string.
+//
+// Return value: string
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT string SimpleItoa(int i);
+LIBPROTOBUF_EXPORT string SimpleItoa(unsigned int i);
+LIBPROTOBUF_EXPORT string SimpleItoa(long i);
+LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long i);
+LIBPROTOBUF_EXPORT string SimpleItoa(long long i);
+LIBPROTOBUF_EXPORT 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
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT string SimpleDtoa(double value);
+LIBPROTOBUF_EXPORT string SimpleFtoa(float value);
+
+LIBPROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
+LIBPROTOBUF_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;
+
+// ----------------------------------------------------------------------
+// NoLocaleStrtod()
+// Exactly like strtod(), except it always behaves as if in the "C"
+// locale (i.e. decimal points must be '.'s).
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr);
+
+} // namespace protobuf
+} // namespace google
+
+#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 00000000..58ffd32e
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil_unittest.cc
@@ -0,0 +1,68 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+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, NULL);
+ ASSERT_TRUE(old_locale_cstr != NULL);
+ string old_locale = old_locale_cstr;
+
+ // Set the locale to "C".
+ ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != NULL);
+
+ EXPECT_EQ(1.5, NoLocaleStrtod("1.5", NULL));
+ EXPECT_EQ("1.5", SimpleDtoa(1.5));
+ EXPECT_EQ("1.5", SimpleFtoa(1.5));
+
+ // Verify that the endptr is set correctly even if not all text was parsed.
+ const char* text = "1.5f";
+ char* endptr;
+ EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
+ EXPECT_EQ(3, endptr - text);
+
+ if (setlocale(LC_NUMERIC, "es_ES") == NULL &&
+ setlocale(LC_NUMERIC, "es_ES.utf8") == NULL) {
+ // 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, NoLocaleStrtod("1.5", NULL));
+ EXPECT_EQ("1.5", SimpleDtoa(1.5));
+ EXPECT_EQ("1.5", SimpleFtoa(1.5));
+ EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
+ EXPECT_EQ(3, endptr - text);
+ }
+
+ // Return to original locale.
+ setlocale(LC_NUMERIC, old_locale.c_str());
+}
+
+} // 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 00000000..340be5e8
--- /dev/null
+++ b/src/google/protobuf/stubs/substitute.cc
@@ -0,0 +1,120 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util-inl.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] != NULL && args_array[count]->size() != -1) {
+ ++count;
+ }
+ return count;
+}
+
+string Substitute(
+ 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) {
+ string result;
+ SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8, arg9);
+ return result;
+}
+
+void SubstituteAndAppend(
+ 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, NULL
+ };
+
+ // 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])) {
+ const SubstituteArg* src = args_array[format[i+1] - '0'];
+ 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 00000000..143e4828
--- /dev/null
+++ b/src/google/protobuf/stubs/substitute.h
@@ -0,0 +1,156 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// from google3/strings/substitute.h
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+
+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 string& value)
+ : text_(value.data()), size_(value.size()) {}
+
+ // Indicates that no argument was given.
+ inline explicit SubstituteArg()
+ : text_(NULL), 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
+
+LIBPROTOBUF_EXPORT string Substitute(
+ 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());
+
+LIBPROTOBUF_EXPORT void SubstituteAndAppend(
+ 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
+
+#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
new file mode 100644
index 00000000..1525e94f
--- /dev/null
+++ b/src/google/protobuf/test_util.cc
@@ -0,0 +1,1912 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+void TestUtil::SetAllFields(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->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.
+ message->GetReflection()->SetString(
+ message->GetDescriptor()->FindFieldByName("optional_string_piece"),
+ "124");
+ message->GetReflection()->SetString(
+ message->GetDescriptor()->FindFieldByName("optional_cord"),
+ "125");
+
+ // -----------------------------------------------------------------
+
+ 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_nested_enum (unittest::TestAllTypes::BAR);
+ message->add_repeated_foreign_enum(unittest::FOREIGN_BAR );
+ message->add_repeated_import_enum (unittest_import::IMPORT_BAR);
+
+ message->GetReflection()->AddString(
+ message->GetDescriptor()->FindFieldByName("repeated_string_piece"),
+ "224");
+ message->GetReflection()->AddString(
+ message->GetDescriptor()->FindFieldByName("repeated_cord"),
+ "225");
+
+ // 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_nested_enum (unittest::TestAllTypes::BAZ);
+ message->add_repeated_foreign_enum(unittest::FOREIGN_BAZ );
+ message->add_repeated_import_enum (unittest_import::IMPORT_BAZ);
+
+ message->GetReflection()->AddString(
+ message->GetDescriptor()->FindFieldByName("repeated_string_piece"),
+ "324");
+ message->GetReflection()->AddString(
+ message->GetDescriptor()->FindFieldByName("repeated_cord"),
+ "325");
+
+ // -----------------------------------------------------------------
+
+ 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);
+
+ message->GetReflection()->SetString(
+ message->GetDescriptor()->FindFieldByName("default_string_piece"),
+ "424");
+ message->GetReflection()->SetString(
+ message->GetDescriptor()->FindFieldByName("default_cord"),
+ "425");
+}
+
+// -------------------------------------------------------------------
+
+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->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);
+
+ message->GetReflection()->SetRepeatedString(
+ message->GetDescriptor()->FindFieldByName("repeated_string_piece"),
+ 1, "424");
+ message->GetReflection()->SetRepeatedString(
+ message->GetDescriptor()->FindFieldByName("repeated_cord"),
+ 1, "425");
+}
+
+// -------------------------------------------------------------------
+
+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.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.has_optional_nested_enum ());
+ EXPECT_TRUE(message.has_optional_foreign_enum());
+ EXPECT_TRUE(message.has_optional_import_enum ());
+
+ EXPECT_TRUE(message.has_optional_string_piece());
+ EXPECT_TRUE(message.has_optional_cord());
+
+ 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(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_nested_enum_size ());
+ ASSERT_EQ(2, message.repeated_foreign_enum_size ());
+ ASSERT_EQ(2, message.repeated_import_enum_size ());
+
+ ASSERT_EQ(2, message.repeated_string_piece_size());
+ ASSERT_EQ(2, message.repeated_cord_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(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_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(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_EQ(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 ());
+
+}
+
+// -------------------------------------------------------------------
+
+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_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_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_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::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_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_EQ(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 ());
+
+}
+
+// -------------------------------------------------------------------
+
+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_nested_enum_size ());
+ ASSERT_EQ(2, message.repeated_foreign_enum_size ());
+ ASSERT_EQ(2, message.repeated_import_enum_size ());
+
+ ASSERT_EQ(2, message.repeated_string_piece_size());
+ ASSERT_EQ(2, message.repeated_cord_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(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_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(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));
+
+}
+
+// ===================================================================
+// 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 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->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_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_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");
+}
+
+// -------------------------------------------------------------------
+
+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");
+}
+
+// -------------------------------------------------------------------
+
+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->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");
+}
+
+// -------------------------------------------------------------------
+
+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.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.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_EQ(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));
+
+ // -----------------------------------------------------------------
+
+ 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_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_EQ(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(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_EQ(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(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_EQ(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));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectExtensionsClear(
+ const unittest::TestAllExtensions& message) {
+ string serialized;
+ ASSERT_TRUE(message.SerializeToString(&serialized));
+ EXPECT_EQ("", serialized);
+ EXPECT_EQ(0, message.ByteSize());
+
+ // 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_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_EQ(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_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());
+
+ // 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_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_EQ(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));
+}
+
+// -------------------------------------------------------------------
+
+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_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_EQ(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(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_EQ(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(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));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectAllFieldsAndExtensionsInOrder(const string& serialized) {
+ // We set each field individually, serialize separately, and concatenate all
+ // the strings in canonical order to determine the expected serialization.
+ 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);
+}
+
+// ===================================================================
+
+TestUtil::ReflectionTester::ReflectionTester(
+ const Descriptor* base_descriptor)
+ : base_descriptor_(base_descriptor) {
+
+ const DescriptorPool* pool = base_descriptor->file()->pool();
+
+ nested_b_ =
+ pool->FindFieldByName("protobuf_unittest.TestAllTypes.NestedMessage.bb");
+ foreign_c_ =
+ pool->FindFieldByName("protobuf_unittest.ForeignMessage.c");
+ import_d_ =
+ pool->FindFieldByName("protobuf_unittest_import.ImportMessage.d");
+ nested_foo_ =
+ pool->FindEnumValueByName("protobuf_unittest.TestAllTypes.FOO");
+ nested_bar_ =
+ pool->FindEnumValueByName("protobuf_unittest.TestAllTypes.BAR");
+ nested_baz_ =
+ pool->FindEnumValueByName("protobuf_unittest.TestAllTypes.BAZ");
+ foreign_foo_ =
+ pool->FindEnumValueByName("protobuf_unittest.FOREIGN_FOO");
+ foreign_bar_ =
+ pool->FindEnumValueByName("protobuf_unittest.FOREIGN_BAR");
+ foreign_baz_ =
+ pool->FindEnumValueByName("protobuf_unittest.FOREIGN_BAZ");
+ import_foo_ =
+ pool->FindEnumValueByName("protobuf_unittest_import.IMPORT_FOO");
+ import_bar_ =
+ pool->FindEnumValueByName("protobuf_unittest_import.IMPORT_BAR");
+ import_baz_ =
+ pool->FindEnumValueByName("protobuf_unittest_import.IMPORT_BAZ");
+
+ if (base_descriptor_->name() == "TestAllExtensions") {
+ group_a_ =
+ pool->FindFieldByName("protobuf_unittest.OptionalGroup_extension.a");
+ repeated_group_a_ =
+ pool->FindFieldByName("protobuf_unittest.RepeatedGroup_extension.a");
+ } else {
+ group_a_ =
+ pool->FindFieldByName("protobuf_unittest.TestAllTypes.OptionalGroup.a");
+ repeated_group_a_ =
+ pool->FindFieldByName("protobuf_unittest.TestAllTypes.RepeatedGroup.a");
+ }
+
+ EXPECT_TRUE(group_a_ != NULL);
+ EXPECT_TRUE(repeated_group_a_ != NULL);
+ EXPECT_TRUE(nested_b_ != NULL);
+ EXPECT_TRUE(foreign_c_ != NULL);
+ EXPECT_TRUE(import_d_ != NULL);
+ EXPECT_TRUE(nested_foo_ != NULL);
+ EXPECT_TRUE(nested_bar_ != NULL);
+ EXPECT_TRUE(nested_baz_ != NULL);
+ EXPECT_TRUE(foreign_foo_ != NULL);
+ EXPECT_TRUE(foreign_bar_ != NULL);
+ EXPECT_TRUE(foreign_baz_ != NULL);
+ EXPECT_TRUE(import_foo_ != NULL);
+ EXPECT_TRUE(import_bar_ != NULL);
+ EXPECT_TRUE(import_baz_ != NULL);
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+const FieldDescriptor* TestUtil::ReflectionTester::F(const string& name) {
+ const FieldDescriptor* result = NULL;
+ if (base_descriptor_->name() == "TestAllExtensions") {
+ result = base_descriptor_->file()->FindExtensionByName(name + "_extension");
+ } else {
+ result = base_descriptor_->FindFieldByName(name);
+ }
+ GOOGLE_CHECK(result != NULL);
+ return result;
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ReflectionTester::SetAllFieldsViaReflection(
+ Message::Reflection* message) {
+ message->SetInt32 (F("optional_int32" ), 101);
+ message->SetInt64 (F("optional_int64" ), 102);
+ message->SetUInt32(F("optional_uint32" ), 103);
+ message->SetUInt64(F("optional_uint64" ), 104);
+ message->SetInt32 (F("optional_sint32" ), 105);
+ message->SetInt64 (F("optional_sint64" ), 106);
+ message->SetUInt32(F("optional_fixed32" ), 107);
+ message->SetUInt64(F("optional_fixed64" ), 108);
+ message->SetInt32 (F("optional_sfixed32"), 109);
+ message->SetInt64 (F("optional_sfixed64"), 110);
+ message->SetFloat (F("optional_float" ), 111);
+ message->SetDouble(F("optional_double" ), 112);
+ message->SetBool (F("optional_bool" ), true);
+ message->SetString(F("optional_string" ), "115");
+ message->SetString(F("optional_bytes" ), "116");
+
+ message->MutableMessage(F("optionalgroup"))
+ ->GetReflection()->SetInt32(group_a_, 117);
+ message->MutableMessage(F("optional_nested_message"))
+ ->GetReflection()->SetInt32(nested_b_, 118);
+ message->MutableMessage(F("optional_foreign_message"))
+ ->GetReflection()->SetInt32(foreign_c_, 119);
+ message->MutableMessage(F("optional_import_message"))
+ ->GetReflection()->SetInt32(import_d_, 120);
+
+ message->SetEnum(F("optional_nested_enum" ), nested_baz_);
+ message->SetEnum(F("optional_foreign_enum"), foreign_baz_);
+ message->SetEnum(F("optional_import_enum" ), import_baz_);
+
+ message->SetString(F("optional_string_piece"), "124");
+ message->SetString(F("optional_cord"), "125");
+
+ // -----------------------------------------------------------------
+
+ message->AddInt32 (F("repeated_int32" ), 201);
+ message->AddInt64 (F("repeated_int64" ), 202);
+ message->AddUInt32(F("repeated_uint32" ), 203);
+ message->AddUInt64(F("repeated_uint64" ), 204);
+ message->AddInt32 (F("repeated_sint32" ), 205);
+ message->AddInt64 (F("repeated_sint64" ), 206);
+ message->AddUInt32(F("repeated_fixed32" ), 207);
+ message->AddUInt64(F("repeated_fixed64" ), 208);
+ message->AddInt32 (F("repeated_sfixed32"), 209);
+ message->AddInt64 (F("repeated_sfixed64"), 210);
+ message->AddFloat (F("repeated_float" ), 211);
+ message->AddDouble(F("repeated_double" ), 212);
+ message->AddBool (F("repeated_bool" ), true);
+ message->AddString(F("repeated_string" ), "215");
+ message->AddString(F("repeated_bytes" ), "216");
+
+ message->AddMessage(F("repeatedgroup"))
+ ->GetReflection()->SetInt32(repeated_group_a_, 217);
+ message->AddMessage(F("repeated_nested_message"))
+ ->GetReflection()->SetInt32(nested_b_, 218);
+ message->AddMessage(F("repeated_foreign_message"))
+ ->GetReflection()->SetInt32(foreign_c_, 219);
+ message->AddMessage(F("repeated_import_message"))
+ ->GetReflection()->SetInt32(import_d_, 220);
+
+ message->AddEnum(F("repeated_nested_enum" ), nested_bar_);
+ message->AddEnum(F("repeated_foreign_enum"), foreign_bar_);
+ message->AddEnum(F("repeated_import_enum" ), import_bar_);
+
+ message->AddString(F("repeated_string_piece"), "224");
+ message->AddString(F("repeated_cord"), "225");
+
+ // Add a second one of each field.
+ message->AddInt32 (F("repeated_int32" ), 301);
+ message->AddInt64 (F("repeated_int64" ), 302);
+ message->AddUInt32(F("repeated_uint32" ), 303);
+ message->AddUInt64(F("repeated_uint64" ), 304);
+ message->AddInt32 (F("repeated_sint32" ), 305);
+ message->AddInt64 (F("repeated_sint64" ), 306);
+ message->AddUInt32(F("repeated_fixed32" ), 307);
+ message->AddUInt64(F("repeated_fixed64" ), 308);
+ message->AddInt32 (F("repeated_sfixed32"), 309);
+ message->AddInt64 (F("repeated_sfixed64"), 310);
+ message->AddFloat (F("repeated_float" ), 311);
+ message->AddDouble(F("repeated_double" ), 312);
+ message->AddBool (F("repeated_bool" ), false);
+ message->AddString(F("repeated_string" ), "315");
+ message->AddString(F("repeated_bytes" ), "316");
+
+ message->AddMessage(F("repeatedgroup"))
+ ->GetReflection()->SetInt32(repeated_group_a_, 317);
+ message->AddMessage(F("repeated_nested_message"))
+ ->GetReflection()->SetInt32(nested_b_, 318);
+ message->AddMessage(F("repeated_foreign_message"))
+ ->GetReflection()->SetInt32(foreign_c_, 319);
+ message->AddMessage(F("repeated_import_message"))
+ ->GetReflection()->SetInt32(import_d_, 320);
+
+ message->AddEnum(F("repeated_nested_enum" ), nested_baz_);
+ message->AddEnum(F("repeated_foreign_enum"), foreign_baz_);
+ message->AddEnum(F("repeated_import_enum" ), import_baz_);
+
+ message->AddString(F("repeated_string_piece"), "324");
+ message->AddString(F("repeated_cord"), "325");
+
+ // -----------------------------------------------------------------
+
+ message->SetInt32 (F("default_int32" ), 401);
+ message->SetInt64 (F("default_int64" ), 402);
+ message->SetUInt32(F("default_uint32" ), 403);
+ message->SetUInt64(F("default_uint64" ), 404);
+ message->SetInt32 (F("default_sint32" ), 405);
+ message->SetInt64 (F("default_sint64" ), 406);
+ message->SetUInt32(F("default_fixed32" ), 407);
+ message->SetUInt64(F("default_fixed64" ), 408);
+ message->SetInt32 (F("default_sfixed32"), 409);
+ message->SetInt64 (F("default_sfixed64"), 410);
+ message->SetFloat (F("default_float" ), 411);
+ message->SetDouble(F("default_double" ), 412);
+ message->SetBool (F("default_bool" ), false);
+ message->SetString(F("default_string" ), "415");
+ message->SetString(F("default_bytes" ), "416");
+
+ message->SetEnum(F("default_nested_enum" ), nested_foo_);
+ message->SetEnum(F("default_foreign_enum"), foreign_foo_);
+ message->SetEnum(F("default_import_enum" ), import_foo_);
+
+ message->SetString(F("default_string_piece"), "424");
+ message->SetString(F("default_cord"), "425");
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection(
+ const Message::Reflection& message) {
+ string scratch;
+
+ EXPECT_TRUE(message.HasField(F("optional_int32" )));
+ EXPECT_TRUE(message.HasField(F("optional_int64" )));
+ EXPECT_TRUE(message.HasField(F("optional_uint32" )));
+ EXPECT_TRUE(message.HasField(F("optional_uint64" )));
+ EXPECT_TRUE(message.HasField(F("optional_sint32" )));
+ EXPECT_TRUE(message.HasField(F("optional_sint64" )));
+ EXPECT_TRUE(message.HasField(F("optional_fixed32" )));
+ EXPECT_TRUE(message.HasField(F("optional_fixed64" )));
+ EXPECT_TRUE(message.HasField(F("optional_sfixed32")));
+ EXPECT_TRUE(message.HasField(F("optional_sfixed64")));
+ EXPECT_TRUE(message.HasField(F("optional_float" )));
+ EXPECT_TRUE(message.HasField(F("optional_double" )));
+ EXPECT_TRUE(message.HasField(F("optional_bool" )));
+ EXPECT_TRUE(message.HasField(F("optional_string" )));
+ EXPECT_TRUE(message.HasField(F("optional_bytes" )));
+
+ EXPECT_TRUE(message.HasField(F("optionalgroup" )));
+ EXPECT_TRUE(message.HasField(F("optional_nested_message" )));
+ EXPECT_TRUE(message.HasField(F("optional_foreign_message")));
+ EXPECT_TRUE(message.HasField(F("optional_import_message" )));
+
+ EXPECT_TRUE(message.GetMessage(F("optionalgroup"))
+ .GetReflection()->HasField(group_a_));
+ EXPECT_TRUE(message.GetMessage(F("optional_nested_message"))
+ .GetReflection()->HasField(nested_b_));
+ EXPECT_TRUE(message.GetMessage(F("optional_foreign_message"))
+ .GetReflection()->HasField(foreign_c_));
+ EXPECT_TRUE(message.GetMessage(F("optional_import_message"))
+ .GetReflection()->HasField(import_d_));
+
+ EXPECT_TRUE(message.HasField(F("optional_nested_enum" )));
+ EXPECT_TRUE(message.HasField(F("optional_foreign_enum")));
+ EXPECT_TRUE(message.HasField(F("optional_import_enum" )));
+
+ EXPECT_TRUE(message.HasField(F("optional_string_piece")));
+ EXPECT_TRUE(message.HasField(F("optional_cord")));
+
+ EXPECT_EQ(101 , message.GetInt32 (F("optional_int32" )));
+ EXPECT_EQ(102 , message.GetInt64 (F("optional_int64" )));
+ EXPECT_EQ(103 , message.GetUInt32(F("optional_uint32" )));
+ EXPECT_EQ(104 , message.GetUInt64(F("optional_uint64" )));
+ EXPECT_EQ(105 , message.GetInt32 (F("optional_sint32" )));
+ EXPECT_EQ(106 , message.GetInt64 (F("optional_sint64" )));
+ EXPECT_EQ(107 , message.GetUInt32(F("optional_fixed32" )));
+ EXPECT_EQ(108 , message.GetUInt64(F("optional_fixed64" )));
+ EXPECT_EQ(109 , message.GetInt32 (F("optional_sfixed32")));
+ EXPECT_EQ(110 , message.GetInt64 (F("optional_sfixed64")));
+ EXPECT_EQ(111 , message.GetFloat (F("optional_float" )));
+ EXPECT_EQ(112 , message.GetDouble(F("optional_double" )));
+ EXPECT_EQ(true , message.GetBool (F("optional_bool" )));
+ EXPECT_EQ("115", message.GetString(F("optional_string" )));
+ EXPECT_EQ("116", message.GetString(F("optional_bytes" )));
+
+ EXPECT_EQ("115", message.GetStringReference(F("optional_string"), &scratch));
+ EXPECT_EQ("116", message.GetStringReference(F("optional_bytes" ), &scratch));
+
+ EXPECT_EQ(117, message.GetMessage(F("optionalgroup"))
+ .GetReflection()->GetInt32(group_a_));
+ EXPECT_EQ(118, message.GetMessage(F("optional_nested_message"))
+ .GetReflection()->GetInt32(nested_b_));
+ EXPECT_EQ(119, message.GetMessage(F("optional_foreign_message"))
+ .GetReflection()->GetInt32(foreign_c_));
+ EXPECT_EQ(120, message.GetMessage(F("optional_import_message"))
+ .GetReflection()->GetInt32(import_d_));
+
+ EXPECT_EQ( nested_baz_, message.GetEnum(F("optional_nested_enum" )));
+ EXPECT_EQ(foreign_baz_, message.GetEnum(F("optional_foreign_enum")));
+ EXPECT_EQ( import_baz_, message.GetEnum(F("optional_import_enum" )));
+
+ EXPECT_EQ("124", message.GetString(F("optional_string_piece")));
+ EXPECT_EQ("124", message.GetStringReference(F("optional_string_piece"),
+ &scratch));
+
+ EXPECT_EQ("125", message.GetString(F("optional_cord")));
+ EXPECT_EQ("125", message.GetStringReference(F("optional_cord"),
+ &scratch));
+
+ // -----------------------------------------------------------------
+
+ ASSERT_EQ(2, message.FieldSize(F("repeated_int32" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_int64" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_uint32" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_uint64" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_sint32" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_sint64" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_fixed32" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_fixed64" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_sfixed32")));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_sfixed64")));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_float" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_double" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_bool" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_string" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_bytes" )));
+
+ ASSERT_EQ(2, message.FieldSize(F("repeatedgroup" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_nested_message" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_foreign_message")));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_import_message" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_nested_enum" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_foreign_enum" )));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_import_enum" )));
+
+ ASSERT_EQ(2, message.FieldSize(F("repeated_string_piece")));
+ ASSERT_EQ(2, message.FieldSize(F("repeated_cord")));
+
+ EXPECT_EQ(201 , message.GetRepeatedInt32 (F("repeated_int32" ), 0));
+ EXPECT_EQ(202 , message.GetRepeatedInt64 (F("repeated_int64" ), 0));
+ EXPECT_EQ(203 , message.GetRepeatedUInt32(F("repeated_uint32" ), 0));
+ EXPECT_EQ(204 , message.GetRepeatedUInt64(F("repeated_uint64" ), 0));
+ EXPECT_EQ(205 , message.GetRepeatedInt32 (F("repeated_sint32" ), 0));
+ EXPECT_EQ(206 , message.GetRepeatedInt64 (F("repeated_sint64" ), 0));
+ EXPECT_EQ(207 , message.GetRepeatedUInt32(F("repeated_fixed32" ), 0));
+ EXPECT_EQ(208 , message.GetRepeatedUInt64(F("repeated_fixed64" ), 0));
+ EXPECT_EQ(209 , message.GetRepeatedInt32 (F("repeated_sfixed32"), 0));
+ EXPECT_EQ(210 , message.GetRepeatedInt64 (F("repeated_sfixed64"), 0));
+ EXPECT_EQ(211 , message.GetRepeatedFloat (F("repeated_float" ), 0));
+ EXPECT_EQ(212 , message.GetRepeatedDouble(F("repeated_double" ), 0));
+ EXPECT_EQ(true , message.GetRepeatedBool (F("repeated_bool" ), 0));
+ EXPECT_EQ("215", message.GetRepeatedString(F("repeated_string" ), 0));
+ EXPECT_EQ("216", message.GetRepeatedString(F("repeated_bytes" ), 0));
+
+ EXPECT_EQ("215", message.GetRepeatedStringReference(F("repeated_string"),
+ 0, &scratch));
+ EXPECT_EQ("216", message.GetRepeatedStringReference(F("repeated_bytes"),
+ 0, &scratch));
+
+ EXPECT_EQ(217, message.GetRepeatedMessage(F("repeatedgroup"), 0)
+ .GetReflection()->GetInt32(repeated_group_a_));
+ EXPECT_EQ(218, message.GetRepeatedMessage(F("repeated_nested_message"), 0)
+ .GetReflection()->GetInt32(nested_b_));
+ EXPECT_EQ(219, message.GetRepeatedMessage(F("repeated_foreign_message"), 0)
+ .GetReflection()->GetInt32(foreign_c_));
+ EXPECT_EQ(220, message.GetRepeatedMessage(F("repeated_import_message"), 0)
+ .GetReflection()->GetInt32(import_d_));
+
+ EXPECT_EQ( nested_bar_, message.GetRepeatedEnum(F("repeated_nested_enum" ),0));
+ EXPECT_EQ(foreign_bar_, message.GetRepeatedEnum(F("repeated_foreign_enum"),0));
+ EXPECT_EQ( import_bar_, message.GetRepeatedEnum(F("repeated_import_enum" ),0));
+
+ EXPECT_EQ("224", message.GetRepeatedString(F("repeated_string_piece"), 0));
+ EXPECT_EQ("224", message.GetRepeatedStringReference(
+ F("repeated_string_piece"), 0, &scratch));
+
+ EXPECT_EQ("225", message.GetRepeatedString(F("repeated_cord"), 0));
+ EXPECT_EQ("225", message.GetRepeatedStringReference(
+ F("repeated_cord"), 0, &scratch));
+
+ EXPECT_EQ(301 , message.GetRepeatedInt32 (F("repeated_int32" ), 1));
+ EXPECT_EQ(302 , message.GetRepeatedInt64 (F("repeated_int64" ), 1));
+ EXPECT_EQ(303 , message.GetRepeatedUInt32(F("repeated_uint32" ), 1));
+ EXPECT_EQ(304 , message.GetRepeatedUInt64(F("repeated_uint64" ), 1));
+ EXPECT_EQ(305 , message.GetRepeatedInt32 (F("repeated_sint32" ), 1));
+ EXPECT_EQ(306 , message.GetRepeatedInt64 (F("repeated_sint64" ), 1));
+ EXPECT_EQ(307 , message.GetRepeatedUInt32(F("repeated_fixed32" ), 1));
+ EXPECT_EQ(308 , message.GetRepeatedUInt64(F("repeated_fixed64" ), 1));
+ EXPECT_EQ(309 , message.GetRepeatedInt32 (F("repeated_sfixed32"), 1));
+ EXPECT_EQ(310 , message.GetRepeatedInt64 (F("repeated_sfixed64"), 1));
+ EXPECT_EQ(311 , message.GetRepeatedFloat (F("repeated_float" ), 1));
+ EXPECT_EQ(312 , message.GetRepeatedDouble(F("repeated_double" ), 1));
+ EXPECT_EQ(false, message.GetRepeatedBool (F("repeated_bool" ), 1));
+ EXPECT_EQ("315", message.GetRepeatedString(F("repeated_string" ), 1));
+ EXPECT_EQ("316", message.GetRepeatedString(F("repeated_bytes" ), 1));
+
+ EXPECT_EQ("315", message.GetRepeatedStringReference(F("repeated_string"),
+ 1, &scratch));
+ EXPECT_EQ("316", message.GetRepeatedStringReference(F("repeated_bytes"),
+ 1, &scratch));
+
+ EXPECT_EQ(317, message.GetRepeatedMessage(F("repeatedgroup"), 1)
+ .GetReflection()->GetInt32(repeated_group_a_));
+ EXPECT_EQ(318, message.GetRepeatedMessage(F("repeated_nested_message"), 1)
+ .GetReflection()->GetInt32(nested_b_));
+ EXPECT_EQ(319, message.GetRepeatedMessage(F("repeated_foreign_message"), 1)
+ .GetReflection()->GetInt32(foreign_c_));
+ EXPECT_EQ(320, message.GetRepeatedMessage(F("repeated_import_message"), 1)
+ .GetReflection()->GetInt32(import_d_));
+
+ EXPECT_EQ( nested_baz_, message.GetRepeatedEnum(F("repeated_nested_enum" ),1));
+ EXPECT_EQ(foreign_baz_, message.GetRepeatedEnum(F("repeated_foreign_enum"),1));
+ EXPECT_EQ( import_baz_, message.GetRepeatedEnum(F("repeated_import_enum" ),1));
+
+ EXPECT_EQ("324", message.GetRepeatedString(F("repeated_string_piece"), 1));
+ EXPECT_EQ("324", message.GetRepeatedStringReference(
+ F("repeated_string_piece"), 1, &scratch));
+
+ EXPECT_EQ("325", message.GetRepeatedString(F("repeated_cord"), 1));
+ EXPECT_EQ("325", message.GetRepeatedStringReference(
+ F("repeated_cord"), 1, &scratch));
+
+ // -----------------------------------------------------------------
+
+ EXPECT_TRUE(message.HasField(F("default_int32" )));
+ EXPECT_TRUE(message.HasField(F("default_int64" )));
+ EXPECT_TRUE(message.HasField(F("default_uint32" )));
+ EXPECT_TRUE(message.HasField(F("default_uint64" )));
+ EXPECT_TRUE(message.HasField(F("default_sint32" )));
+ EXPECT_TRUE(message.HasField(F("default_sint64" )));
+ EXPECT_TRUE(message.HasField(F("default_fixed32" )));
+ EXPECT_TRUE(message.HasField(F("default_fixed64" )));
+ EXPECT_TRUE(message.HasField(F("default_sfixed32")));
+ EXPECT_TRUE(message.HasField(F("default_sfixed64")));
+ EXPECT_TRUE(message.HasField(F("default_float" )));
+ EXPECT_TRUE(message.HasField(F("default_double" )));
+ EXPECT_TRUE(message.HasField(F("default_bool" )));
+ EXPECT_TRUE(message.HasField(F("default_string" )));
+ EXPECT_TRUE(message.HasField(F("default_bytes" )));
+
+ EXPECT_TRUE(message.HasField(F("default_nested_enum" )));
+ EXPECT_TRUE(message.HasField(F("default_foreign_enum")));
+ EXPECT_TRUE(message.HasField(F("default_import_enum" )));
+
+ EXPECT_TRUE(message.HasField(F("default_string_piece")));
+ EXPECT_TRUE(message.HasField(F("default_cord")));
+
+ EXPECT_EQ(401 , message.GetInt32 (F("default_int32" )));
+ EXPECT_EQ(402 , message.GetInt64 (F("default_int64" )));
+ EXPECT_EQ(403 , message.GetUInt32(F("default_uint32" )));
+ EXPECT_EQ(404 , message.GetUInt64(F("default_uint64" )));
+ EXPECT_EQ(405 , message.GetInt32 (F("default_sint32" )));
+ EXPECT_EQ(406 , message.GetInt64 (F("default_sint64" )));
+ EXPECT_EQ(407 , message.GetUInt32(F("default_fixed32" )));
+ EXPECT_EQ(408 , message.GetUInt64(F("default_fixed64" )));
+ EXPECT_EQ(409 , message.GetInt32 (F("default_sfixed32")));
+ EXPECT_EQ(410 , message.GetInt64 (F("default_sfixed64")));
+ EXPECT_EQ(411 , message.GetFloat (F("default_float" )));
+ EXPECT_EQ(412 , message.GetDouble(F("default_double" )));
+ EXPECT_EQ(false, message.GetBool (F("default_bool" )));
+ EXPECT_EQ("415", message.GetString(F("default_string" )));
+ EXPECT_EQ("416", message.GetString(F("default_bytes" )));
+
+ EXPECT_EQ("415", message.GetStringReference(F("default_string"), &scratch));
+ EXPECT_EQ("416", message.GetStringReference(F("default_bytes" ), &scratch));
+
+ EXPECT_EQ( nested_foo_, message.GetEnum(F("default_nested_enum" )));
+ EXPECT_EQ(foreign_foo_, message.GetEnum(F("default_foreign_enum")));
+ EXPECT_EQ( import_foo_, message.GetEnum(F("default_import_enum" )));
+
+ EXPECT_EQ("424", message.GetString(F("default_string_piece")));
+ EXPECT_EQ("424", message.GetStringReference(F("default_string_piece"),
+ &scratch));
+
+ EXPECT_EQ("425", message.GetString(F("default_cord")));
+ EXPECT_EQ("425", message.GetStringReference(F("default_cord"), &scratch));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ReflectionTester::ExpectClearViaReflection(
+ const Message::Reflection& message) {
+ string scratch;
+
+ // has_blah() should initially be false for all optional fields.
+ EXPECT_FALSE(message.HasField(F("optional_int32" )));
+ EXPECT_FALSE(message.HasField(F("optional_int64" )));
+ EXPECT_FALSE(message.HasField(F("optional_uint32" )));
+ EXPECT_FALSE(message.HasField(F("optional_uint64" )));
+ EXPECT_FALSE(message.HasField(F("optional_sint32" )));
+ EXPECT_FALSE(message.HasField(F("optional_sint64" )));
+ EXPECT_FALSE(message.HasField(F("optional_fixed32" )));
+ EXPECT_FALSE(message.HasField(F("optional_fixed64" )));
+ EXPECT_FALSE(message.HasField(F("optional_sfixed32")));
+ EXPECT_FALSE(message.HasField(F("optional_sfixed64")));
+ EXPECT_FALSE(message.HasField(F("optional_float" )));
+ EXPECT_FALSE(message.HasField(F("optional_double" )));
+ EXPECT_FALSE(message.HasField(F("optional_bool" )));
+ EXPECT_FALSE(message.HasField(F("optional_string" )));
+ EXPECT_FALSE(message.HasField(F("optional_bytes" )));
+
+ EXPECT_FALSE(message.HasField(F("optionalgroup" )));
+ EXPECT_FALSE(message.HasField(F("optional_nested_message" )));
+ EXPECT_FALSE(message.HasField(F("optional_foreign_message")));
+ EXPECT_FALSE(message.HasField(F("optional_import_message" )));
+
+ EXPECT_FALSE(message.HasField(F("optional_nested_enum" )));
+ EXPECT_FALSE(message.HasField(F("optional_foreign_enum")));
+ EXPECT_FALSE(message.HasField(F("optional_import_enum" )));
+
+ EXPECT_FALSE(message.HasField(F("optional_string_piece")));
+ EXPECT_FALSE(message.HasField(F("optional_cord")));
+
+ // Optional fields without defaults are set to zero or something like it.
+ EXPECT_EQ(0 , message.GetInt32 (F("optional_int32" )));
+ EXPECT_EQ(0 , message.GetInt64 (F("optional_int64" )));
+ EXPECT_EQ(0 , message.GetUInt32(F("optional_uint32" )));
+ EXPECT_EQ(0 , message.GetUInt64(F("optional_uint64" )));
+ EXPECT_EQ(0 , message.GetInt32 (F("optional_sint32" )));
+ EXPECT_EQ(0 , message.GetInt64 (F("optional_sint64" )));
+ EXPECT_EQ(0 , message.GetUInt32(F("optional_fixed32" )));
+ EXPECT_EQ(0 , message.GetUInt64(F("optional_fixed64" )));
+ EXPECT_EQ(0 , message.GetInt32 (F("optional_sfixed32")));
+ EXPECT_EQ(0 , message.GetInt64 (F("optional_sfixed64")));
+ EXPECT_EQ(0 , message.GetFloat (F("optional_float" )));
+ EXPECT_EQ(0 , message.GetDouble(F("optional_double" )));
+ EXPECT_EQ(false, message.GetBool (F("optional_bool" )));
+ EXPECT_EQ("" , message.GetString(F("optional_string" )));
+ EXPECT_EQ("" , message.GetString(F("optional_bytes" )));
+
+ EXPECT_EQ("", message.GetStringReference(F("optional_string"), &scratch));
+ EXPECT_EQ("", message.GetStringReference(F("optional_bytes" ), &scratch));
+
+ // Embedded messages should also be clear.
+ EXPECT_FALSE(message.GetMessage(F("optionalgroup"))
+ .GetReflection()->HasField(group_a_));
+ EXPECT_FALSE(message.GetMessage(F("optional_nested_message"))
+ .GetReflection()->HasField(nested_b_));
+ EXPECT_FALSE(message.GetMessage(F("optional_foreign_message"))
+ .GetReflection()->HasField(foreign_c_));
+ EXPECT_FALSE(message.GetMessage(F("optional_import_message"))
+ .GetReflection()->HasField(import_d_));
+
+ EXPECT_EQ(0, message.GetMessage(F("optionalgroup"))
+ .GetReflection()->GetInt32(group_a_));
+ EXPECT_EQ(0, message.GetMessage(F("optional_nested_message"))
+ .GetReflection()->GetInt32(nested_b_));
+ EXPECT_EQ(0, message.GetMessage(F("optional_foreign_message"))
+ .GetReflection()->GetInt32(foreign_c_));
+ EXPECT_EQ(0, message.GetMessage(F("optional_import_message"))
+ .GetReflection()->GetInt32(import_d_));
+
+ // Enums without defaults are set to the first value in the enum.
+ EXPECT_EQ( nested_foo_, message.GetEnum(F("optional_nested_enum" )));
+ EXPECT_EQ(foreign_foo_, message.GetEnum(F("optional_foreign_enum")));
+ EXPECT_EQ( import_foo_, message.GetEnum(F("optional_import_enum" )));
+
+ EXPECT_EQ("", message.GetString(F("optional_string_piece")));
+ EXPECT_EQ("", message.GetStringReference(F("optional_string_piece"),
+ &scratch));
+
+ EXPECT_EQ("", message.GetString(F("optional_cord")));
+ EXPECT_EQ("", message.GetStringReference(F("optional_cord"), &scratch));
+
+ // Repeated fields are empty.
+ EXPECT_EQ(0, message.FieldSize(F("repeated_int32" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_int64" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_uint32" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_uint64" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_sint32" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_sint64" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_fixed32" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_fixed64" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_sfixed32")));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_sfixed64")));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_float" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_double" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_bool" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_string" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_bytes" )));
+
+ EXPECT_EQ(0, message.FieldSize(F("repeatedgroup" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_nested_message" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_foreign_message")));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_import_message" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_nested_enum" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_foreign_enum" )));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_import_enum" )));
+
+ EXPECT_EQ(0, message.FieldSize(F("repeated_string_piece")));
+ EXPECT_EQ(0, message.FieldSize(F("repeated_cord")));
+
+ // has_blah() should also be false for all default fields.
+ EXPECT_FALSE(message.HasField(F("default_int32" )));
+ EXPECT_FALSE(message.HasField(F("default_int64" )));
+ EXPECT_FALSE(message.HasField(F("default_uint32" )));
+ EXPECT_FALSE(message.HasField(F("default_uint64" )));
+ EXPECT_FALSE(message.HasField(F("default_sint32" )));
+ EXPECT_FALSE(message.HasField(F("default_sint64" )));
+ EXPECT_FALSE(message.HasField(F("default_fixed32" )));
+ EXPECT_FALSE(message.HasField(F("default_fixed64" )));
+ EXPECT_FALSE(message.HasField(F("default_sfixed32")));
+ EXPECT_FALSE(message.HasField(F("default_sfixed64")));
+ EXPECT_FALSE(message.HasField(F("default_float" )));
+ EXPECT_FALSE(message.HasField(F("default_double" )));
+ EXPECT_FALSE(message.HasField(F("default_bool" )));
+ EXPECT_FALSE(message.HasField(F("default_string" )));
+ EXPECT_FALSE(message.HasField(F("default_bytes" )));
+
+ EXPECT_FALSE(message.HasField(F("default_nested_enum" )));
+ EXPECT_FALSE(message.HasField(F("default_foreign_enum")));
+ EXPECT_FALSE(message.HasField(F("default_import_enum" )));
+
+ EXPECT_FALSE(message.HasField(F("default_string_piece")));
+ EXPECT_FALSE(message.HasField(F("default_cord")));
+
+ // Fields with defaults have their default values (duh).
+ EXPECT_EQ( 41 , message.GetInt32 (F("default_int32" )));
+ EXPECT_EQ( 42 , message.GetInt64 (F("default_int64" )));
+ EXPECT_EQ( 43 , message.GetUInt32(F("default_uint32" )));
+ EXPECT_EQ( 44 , message.GetUInt64(F("default_uint64" )));
+ EXPECT_EQ(-45 , message.GetInt32 (F("default_sint32" )));
+ EXPECT_EQ( 46 , message.GetInt64 (F("default_sint64" )));
+ EXPECT_EQ( 47 , message.GetUInt32(F("default_fixed32" )));
+ EXPECT_EQ( 48 , message.GetUInt64(F("default_fixed64" )));
+ EXPECT_EQ( 49 , message.GetInt32 (F("default_sfixed32")));
+ EXPECT_EQ(-50 , message.GetInt64 (F("default_sfixed64")));
+ EXPECT_EQ( 51.5 , message.GetFloat (F("default_float" )));
+ EXPECT_EQ( 52e3 , message.GetDouble(F("default_double" )));
+ EXPECT_EQ(true , message.GetBool (F("default_bool" )));
+ EXPECT_EQ("hello", message.GetString(F("default_string" )));
+ EXPECT_EQ("world", message.GetString(F("default_bytes" )));
+
+ EXPECT_EQ("hello", message.GetStringReference(F("default_string"), &scratch));
+ EXPECT_EQ("world", message.GetStringReference(F("default_bytes" ), &scratch));
+
+ EXPECT_EQ( nested_bar_, message.GetEnum(F("default_nested_enum" )));
+ EXPECT_EQ(foreign_bar_, message.GetEnum(F("default_foreign_enum")));
+ EXPECT_EQ( import_bar_, message.GetEnum(F("default_import_enum" )));
+
+ EXPECT_EQ("abc", message.GetString(F("default_string_piece")));
+ EXPECT_EQ("abc", message.GetStringReference(F("default_string_piece"),
+ &scratch));
+
+ EXPECT_EQ("123", message.GetString(F("default_cord")));
+ EXPECT_EQ("123", message.GetStringReference(F("default_cord"), &scratch));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
+ Message::Reflection* message) {
+ message->SetRepeatedInt32 (F("repeated_int32" ), 1, 501);
+ message->SetRepeatedInt64 (F("repeated_int64" ), 1, 502);
+ message->SetRepeatedUInt32(F("repeated_uint32" ), 1, 503);
+ message->SetRepeatedUInt64(F("repeated_uint64" ), 1, 504);
+ message->SetRepeatedInt32 (F("repeated_sint32" ), 1, 505);
+ message->SetRepeatedInt64 (F("repeated_sint64" ), 1, 506);
+ message->SetRepeatedUInt32(F("repeated_fixed32" ), 1, 507);
+ message->SetRepeatedUInt64(F("repeated_fixed64" ), 1, 508);
+ message->SetRepeatedInt32 (F("repeated_sfixed32"), 1, 509);
+ message->SetRepeatedInt64 (F("repeated_sfixed64"), 1, 510);
+ message->SetRepeatedFloat (F("repeated_float" ), 1, 511);
+ message->SetRepeatedDouble(F("repeated_double" ), 1, 512);
+ message->SetRepeatedBool (F("repeated_bool" ), 1, true);
+ message->SetRepeatedString(F("repeated_string" ), 1, "515");
+ message->SetRepeatedString(F("repeated_bytes" ), 1, "516");
+
+ message->MutableRepeatedMessage(F("repeatedgroup"), 1)
+ ->GetReflection()->SetInt32(repeated_group_a_, 517);
+ message->MutableRepeatedMessage(F("repeated_nested_message"), 1)
+ ->GetReflection()->SetInt32(nested_b_, 518);
+ message->MutableRepeatedMessage(F("repeated_foreign_message"), 1)
+ ->GetReflection()->SetInt32(foreign_c_, 519);
+ message->MutableRepeatedMessage(F("repeated_import_message"), 1)
+ ->GetReflection()->SetInt32(import_d_, 520);
+
+ message->SetRepeatedEnum(F("repeated_nested_enum" ), 1, nested_foo_);
+ message->SetRepeatedEnum(F("repeated_foreign_enum"), 1, foreign_foo_);
+ message->SetRepeatedEnum(F("repeated_import_enum" ), 1, import_foo_);
+
+ message->SetRepeatedString(F("repeated_string_piece"), 1, "524");
+ message->SetRepeatedString(F("repeated_cord"), 1, "525");
+}
+
+} // 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 00000000..4157d095
--- /dev/null
+++ b/src/google/protobuf/test_util.h
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <stack>
+#include <string>
+#include <google/protobuf/message.h>
+#include <google/protobuf/unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+namespace unittest = protobuf_unittest;
+namespace unittest_import = protobuf_unittest_import;
+
+class TestUtil {
+ public:
+ // Set every field in the message to a unique value.
+ static void SetAllFields(unittest::TestAllTypes* message);
+ static void SetAllExtensions(unittest::TestAllExtensions* message);
+ static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message);
+
+ // Use the repeated versions of the set_*() accessors to modify all the
+ // repeated fields of the messsage (which should already have been
+ // initialized with SetAllFields()). SetAllFields() itself only tests
+ // the add_*() accessors.
+ static void ModifyRepeatedFields(unittest::TestAllTypes* message);
+ static void ModifyRepeatedExtensions(unittest::TestAllExtensions* message);
+
+ // Check that all fields have the values that they should have after
+ // SetAllFields() is called.
+ static void ExpectAllFieldsSet(const unittest::TestAllTypes& message);
+ static void ExpectAllExtensionsSet(
+ const unittest::TestAllExtensions& message);
+
+ // Expect that the message is modified as would be expected from
+ // ModifyRepeatedFields().
+ static void ExpectRepeatedFieldsModified(
+ const unittest::TestAllTypes& message);
+ static void ExpectRepeatedExtensionsModified(
+ const unittest::TestAllExtensions& message);
+
+ // Check that all fields have their default values.
+ static void ExpectClear(const unittest::TestAllTypes& message);
+ static void ExpectExtensionsClear(const unittest::TestAllExtensions& message);
+
+ // Check that the passed-in serialization is the canonical serialization we
+ // expect for a TestFieldOrderings message filled in by
+ // SetAllFieldsAndExtensions().
+ static void ExpectAllFieldsAndExtensionsInOrder(const string& serialized);
+
+ // Like above, but use the reflection interface.
+ 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::Reflection* message);
+ void ModifyRepeatedFieldsViaReflection(Message::Reflection* message);
+ void ExpectAllFieldsSetViaReflection(
+ const Message::Reflection& message);
+ void ExpectClearViaReflection(const Message::Reflection& message);
+
+ private:
+ const FieldDescriptor* F(const 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 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_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionTester);
+ };
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TestUtil);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_TEST_UTIL_H__
diff --git a/src/google/protobuf/testdata/golden_message b/src/google/protobuf/testdata/golden_message
new file mode 100644
index 00000000..94898e49
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message
Binary files differ
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 00000000..feea8f7b
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data.txt
@@ -0,0 +1,116 @@
+optional_int32: 101
+optional_int64: 102
+optional_uint32: 103
+optional_uint64: 104
+optional_sint32: 105
+optional_sint64: 106
+optional_fixed32: 107
+optional_fixed64: 108
+optional_sfixed32: 109
+optional_sfixed64: 110
+optional_float: 111
+optional_double: 112
+optional_bool: true
+optional_string: "115"
+optional_bytes: "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"
+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"
+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"
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 00000000..057beae8
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
@@ -0,0 +1,116 @@
+[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.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.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"
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
new file mode 100644
index 00000000..473d6919
--- /dev/null
+++ b/src/google/protobuf/testing/file.cc
@@ -0,0 +1,157 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <io.h>
+#include <direct.h>
+#else
+#include <dirent.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _WIN32
+#define mkdir(name, mode) mkdir(name)
+// Windows doesn't have symbolic links.
+#define lstat stat
+#ifndef F_OK
+#define F_OK 00 // not defined by MSVC for whatever reason
+#endif
+#endif
+
+bool File::Exists(const string& name) {
+ return access(name.c_str(), F_OK) == 0;
+}
+
+bool File::ReadFileToString(const string& name, string* output) {
+ char buffer[1024];
+ FILE* file = fopen(name.c_str(), "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 string& name, string* output) {
+ GOOGLE_CHECK(ReadFileToString(name, output)) << "Could not read: " << name;
+}
+
+void File::WriteStringToFileOrDie(const string& contents, const string& name) {
+ FILE* file = fopen(name.c_str(), "wb");
+ GOOGLE_CHECK(file != NULL);
+ GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file),
+ contents.size());
+ GOOGLE_CHECK(fclose(file) == 0);
+}
+
+bool File::CreateDir(const string& name, int mode) {
+ return mkdir(name.c_str(), mode) == 0;
+}
+
+bool File::RecursivelyCreateDir(const string& path, int mode) {
+ if (CreateDir(path, mode)) return true;
+
+ // Try creating the parent.
+ string::size_type slashpos = path.find_first_of('/');
+ if (slashpos == string::npos) {
+ // No parent given.
+ return false;
+ }
+
+ return RecursivelyCreateDir(path.substr(0, slashpos), mode) &&
+ CreateDir(path, mode);
+}
+
+void File::DeleteRecursively(const string& name,
+ void* dummy1, void* dummy2) {
+ // 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_DATA find_data;
+ HANDLE find_handle = FindFirstFile((name + "/*").c_str(), &find_data);
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ // Just delete it, whatever it is.
+ DeleteFile(name.c_str());
+ RemoveDirectory(name.c_str());
+ return;
+ }
+
+ do {
+ string entry_name = find_data.cFileName;
+ if (entry_name != "." && entry_name != "..") {
+ string path = name + "/" + entry_name;
+ if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ DeleteRecursively(path, NULL, NULL);
+ RemoveDirectory(path.c_str());
+ } else {
+ DeleteFile(path.c_str());
+ }
+ }
+ } while(FindNextFile(find_handle, &find_data));
+ FindClose(find_handle);
+
+ RemoveDirectory(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;
+ 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
+}
+
+} // 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 00000000..93335f1a
--- /dev/null
+++ b/src/google/protobuf/testing/file.h
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 string& name);
+
+ // Read an entire file to a string. Return true if successful, false
+ // otherwise.
+ static bool ReadFileToString(const string& name, string* output);
+
+ // Same as above, but crash on failure.
+ static void ReadFileToStringOrDie(const string& name, string* output);
+
+ // Create a file and write a string to it.
+ static void WriteStringToFileOrDie(const string& contents,
+ const string& name);
+
+ // Create a directory.
+ static bool CreateDir(const string& name, int mode);
+
+ // Create a directory and all parent directories if necessary.
+ static bool RecursivelyCreateDir(const 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 string& name,
+ void* dummy1, void* dummy2);
+
+ 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 00000000..aabc657f
--- /dev/null
+++ b/src/google/protobuf/testing/googletest.cc
@@ -0,0 +1,189 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/stubs/strutil.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+#include <io.h>
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _WIN32
+#define mkdir(name, mode) mkdir(name)
+#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
+
+string TestSourceDir() {
+#ifdef _MSC_VER
+ // Look for the "src" directory.
+ string prefix = ".";
+
+ while (!File::Exists(prefix + "/src/google/protobuf")) {
+ 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";
+#else
+ // automake sets the "srcdir" environment variable.
+ char* result = getenv("srcdir");
+ if (result == NULL) {
+ // Otherwise, the test must be run from the source directory.
+ return ".";
+ } else {
+ return result;
+ }
+#endif
+}
+
+namespace {
+
+string GetTemporaryDirectoryName() {
+ // 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.
+ string result = tmpnam(NULL);
+#ifdef _WIN32
+ // 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);
+ }
+#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);
+ }
+ }
+
+ 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:
+ string name_;
+};
+
+TempDirDeleter temp_dir_deleter_;
+
+} // namespace
+
+string TestTempDir() {
+ return temp_dir_deleter_.GetTempDir();
+}
+
+static string stderr_capture_filename_;
+static int original_stderr_ = -1;
+
+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);
+}
+
+string GetCapturedTestStderr() {
+ GOOGLE_CHECK_NE(original_stderr_, -1) << "Not capturing.";
+
+ close(2);
+ dup2(original_stderr_, 2);
+ original_stderr_ = -1;
+
+ 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 vector<string>& ScopedMemoryLog::GetMessages(LogLevel dummy) const {
+ GOOGLE_CHECK_EQ(dummy, ERROR);
+ return messages_;
+}
+
+void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename,
+ int line, const string& message) {
+ GOOGLE_CHECK(active_log_ != NULL);
+ if (level == ERROR) {
+ active_log_->messages_.push_back(message);
+ }
+}
+
+} // 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 00000000..9420641a
--- /dev/null
+++ b/src/google/protobuf/testing/googletest.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// emulates google3/testing/base/public/googletest.h
+
+#ifndef GOOGLE_PROTOBUF_GOOGLETEST_H__
+#define GOOGLE_PROTOBUF_GOOGLETEST_H__
+
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// When running unittests, get the directory containing the source code.
+string TestSourceDir();
+
+// When running unittests, get a directory where temporary files may be
+// placed.
+string TestTempDir();
+
+// Capture all text written to stderr.
+void CaptureTestStderr();
+
+// Stop capturing stderr and return the text captured.
+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.
+static const LogLevel ERROR = LOGLEVEL_ERROR;
+
+// 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 logged. The internal version of this class
+ // would only fetch messages at the given security level, but the protobuf
+ // open source version ignores the argument since we always pass ERROR
+ // anyway.
+ const vector<string>& GetMessages(LogLevel dummy) const;
+
+ private:
+ vector<string> messages_;
+ LogHandler* old_handler_;
+
+ static void HandleLog(LogLevel level, const char* filename, int line,
+ const 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/text_format.cc b/src/google/protobuf/text_format.cc
new file mode 100644
index 00000000..63a64db1
--- /dev/null
+++ b/src/google/protobuf/text_format.cc
@@ -0,0 +1,941 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: jschorr@google.com (Joseph Schorr)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <float.h>
+#include <math.h>
+#include <stack>
+#include <limits>
+
+#include <google/protobuf/text_format.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+
+string Message::DebugString() const {
+ string debug_string;
+ io::StringOutputStream output_stream(&debug_string);
+
+ TextFormat::Print(*this, &output_stream);
+
+ return debug_string;
+}
+
+string Message::ShortDebugString() const {
+ // TODO(kenton): Make TextFormat support this natively instead of using
+ // DebugString() and munging the result.
+ string result = DebugString();
+
+ // Replace each contiguous range of whitespace (including newlines) with a
+ // single space.
+ for (int i = 0; i < result.size(); i++) {
+ int pos = i;
+ while (isspace(result[pos])) ++pos;
+ if (pos > i) result.replace(i, pos - i, " ");
+ }
+
+ return result;
+}
+
+void Message::PrintDebugString() const {
+ printf("%s", DebugString().c_str());
+}
+
+// ===========================================================================
+// Internal class for parsing an ASCII representation of a Protocol Message.
+// This class makes use of the Protocol Message compiler's tokenizer found
+// in //google/protobuf/io/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::ParserImpl {
+ public:
+ ParserImpl(io::ZeroCopyInputStream* input_stream,
+ io::ErrorCollector* error_collector)
+ : error_collector_(error_collector),
+ tokenizer_error_collector_(this),
+ tokenizer_(input_stream, &tokenizer_error_collector_),
+ root_message_type_(NULL) {
+ // 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);
+
+ // 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) {
+ Message::Reflection* reflection = output->GetReflection();
+ const Descriptor* descriptor = output->GetDescriptor();
+ root_message_type_ = descriptor;
+
+ // Consume fields until we cannot do so anymore.
+ while(true) {
+ if (LookingAtType(io::Tokenizer::TYPE_END)) {
+ return true;
+ }
+
+ DO(ConsumeField(reflection, descriptor));
+ }
+ }
+
+ void ReportError(int line, int col, const string& message) {
+ if (error_collector_ == NULL) {
+ 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);
+ }
+ }
+
+ private:
+ 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 string& message) {
+ ReportError(tokenizer_.current().line, tokenizer_.current().column,
+ message);
+ }
+
+ // Consumes the specified message with the given starting delimeter.
+ // This method checks to see that the end delimeter at the conclusion of
+ // the consumption matches the starting delimeter passed in here.
+ bool ConsumeMessage(Message* message, const string delimeter) {
+ Message::Reflection* reflection = message->GetReflection();
+ const Descriptor* descriptor = message->GetDescriptor();
+
+ while (!LookingAt(">") && !LookingAt("}")) {
+ DO(ConsumeField(reflection, descriptor));
+ }
+
+ // Confirm that we have a valid ending delimeter.
+ DO(Consume(delimeter));
+
+ return true;
+ }
+
+ // Consumes the current field (as returned by the tokenizer) on the
+ // passed in message.
+ bool ConsumeField(Message::Reflection* reflection,
+ const Descriptor* descriptor) {
+ string field_name;
+
+ const FieldDescriptor* field = NULL;
+
+ if (TryConsume("[")) {
+ // Extension.
+ DO(ConsumeIdentifier(&field_name));
+ while (TryConsume(".")) {
+ string part;
+ DO(ConsumeIdentifier(&part));
+ field_name += ".";
+ field_name += part;
+ }
+ DO(Consume("]"));
+
+ field = reflection->FindKnownExtensionByName(field_name);
+
+ if (field == NULL) {
+ ReportError("Extension \"" + field_name + "\" is not defined or "
+ "is not an extension of \"" +
+ descriptor->full_name() + "\".");
+ return false;
+ }
+ } else {
+ DO(ConsumeIdentifier(&field_name));
+
+ 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 == NULL) {
+ 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 != NULL && field->type() != FieldDescriptor::TYPE_GROUP) {
+ field = NULL;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
+ && field->message_type()->name() != field_name) {
+ field = NULL;
+ }
+
+ if (field == NULL) {
+ ReportError("Message type \"" + descriptor->full_name() +
+ "\" has no field named \"" + field_name + "\".");
+ return false;
+ }
+ }
+
+ // Perform special handling for embedded message types.
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ string delimeter;
+
+ // ':' is optional here.
+ TryConsume(":");
+
+ if (TryConsume("<")) {
+ delimeter = ">";
+ } else {
+ DO(Consume("{"));
+ delimeter = "}";
+ }
+
+ if (field->is_repeated()) {
+ DO(ConsumeMessage(reflection->AddMessage(field), delimeter));
+ } else {
+ DO(ConsumeMessage(reflection->MutableMessage(field), delimeter));
+ }
+ } else {
+ DO(Consume(":"));
+ DO(ConsumeFieldValue(reflection, field));
+ }
+
+ return true;
+ }
+
+ bool ConsumeFieldValue(Message::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(field, VALUE); \
+ } else { \
+ reflection->Set##CPPTYPE(field, VALUE); \
+ } \
+
+ switch(field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ int64 value;
+ DO(ConsumeSignedInteger(&value, kint32max));
+ SET_FIELD(Int32, static_cast<int32>(value));
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ uint64 value;
+ DO(ConsumeUnsignedInteger(&value, kuint32max));
+ SET_FIELD(UInt32, static_cast<uint32>(value));
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_INT64: {
+ int64 value;
+ DO(ConsumeSignedInteger(&value, kint64max));
+ SET_FIELD(Int64, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ uint64 value;
+ DO(ConsumeUnsignedInteger(&value, kuint64max));
+ SET_FIELD(UInt64, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ double value;
+ DO(ConsumeDouble(&value));
+ SET_FIELD(Float, static_cast<float>(value));
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value;
+ DO(ConsumeDouble(&value));
+ SET_FIELD(Double, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string value;
+ DO(ConsumeString(&value));
+ SET_FIELD(String, value);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ string value;
+ DO(ConsumeIdentifier(&value));
+
+ if (value == "true") {
+ SET_FIELD(Bool, true);
+ } else if (value == "false") {
+ SET_FIELD(Bool, false);
+ } else {
+ ReportError("Invalid value for boolean field \"" + field->name()
+ + "\". Value: \"" + value + "\".");
+ return false;
+ }
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ string value;
+ DO(ConsumeIdentifier(&value));
+
+ // Find the enumeration value.
+ const EnumDescriptor* enum_type = field->enum_type();
+ const EnumValueDescriptor* enum_value
+ = enum_type->FindValueByName(value);
+
+ if (enum_value == NULL) {
+ ReportError("Unknown enumeration value of \"" + value + "\" for "
+ "field \"" + field->name() + "\".");
+ return false;
+ }
+
+ 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;
+ }
+
+ // Returns true if the current token's text is equal to that specified.
+ bool LookingAt(const 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 IDENTFIER.
+ bool ConsumeIdentifier(string* identifier) {
+ if (!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ ReportError("Expected identifier.");
+ return false;
+ }
+
+ *identifier = tokenizer_.current().text;
+
+ tokenizer_.Next();
+ return true;
+ }
+
+ // Consumes a string and saves its value in the text parameter.
+ // Returns false if the token is not of type STRING.
+ bool ConsumeString(string* text) {
+ if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ ReportError("Expected string.");
+ return false;
+ }
+
+ io::Tokenizer::ParseString(tokenizer_.current().text, text);
+
+ tokenizer_.Next();
+ return true;
+ }
+
+ // Consumes a uint64 and saves its value in the value parameter.
+ // Returns false if the token is not of type INTEGER.
+ bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
+ if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+ ReportError("Expected integer.");
+ return false;
+ }
+
+ if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
+ max_value, value)) {
+ ReportError("Integer out of range.");
+ return false;
+ }
+
+ tokenizer_.Next();
+ return true;
+ }
+
+ // Consumes an int64 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* value, uint64 max_value) {
+ bool negative = false;
+
+ if (TryConsume("-")) {
+ negative = true;
+ // Two's complement always allows one more negative integer than
+ // positive.
+ ++max_value;
+ }
+
+ uint64 unsigned_value;
+
+ DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
+
+ *value = static_cast<int64>(unsigned_value);
+
+ if (negative) {
+ *value = -*value;
+ }
+
+ 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.
+ uint64 integer_value;
+ DO(ConsumeUnsignedInteger(&integer_value, kuint64max));
+
+ *value = static_cast<double>(integer_value);
+ } 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)) {
+ 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.");
+ return false;
+ }
+ } else {
+ ReportError("Expected double.");
+ return false;
+ }
+
+ if (negative) {
+ *value = -*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 string& value) {
+ const string& current_value = tokenizer_.current().text;
+
+ if (current_value != value) {
+ ReportError("Expected \"" + value + "\", found \"" + current_value
+ + "\".");
+ return false;
+ }
+
+ tokenizer_.Next();
+
+ return true;
+ }
+
+ // Attempts to consume the supplied value. Returns false if a the
+ // token found does not match the value specified.
+ bool TryConsume(const string& value) {
+ if (tokenizer_.current().text == value) {
+ tokenizer_.Next();
+ return true;
+ } else {
+ 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::ParserImpl* parser) :
+ parser_(parser) { }
+
+ virtual ~ParserErrorCollector() { };
+
+ virtual void AddError(int line, int column, const string& message) {
+ parser_->ReportError(line, column, message);
+ }
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector);
+ TextFormat::ParserImpl* parser_;
+ };
+
+ io::ErrorCollector* error_collector_;
+ ParserErrorCollector tokenizer_error_collector_;
+ io::Tokenizer tokenizer_;
+ const Descriptor* root_message_type_;
+};
+
+#undef DO
+
+// ===========================================================================
+// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
+// from the Printer found in //google/protobuf/io/printer.h
+class TextFormat::TextGenerator {
+ public:
+ explicit TextGenerator(io::ZeroCopyOutputStream* output)
+ : output_(output),
+ buffer_(NULL),
+ buffer_size_(0),
+ at_start_of_line_(true),
+ failed_(false),
+ indent_("") {
+ }
+
+ ~TextGenerator() {
+ // Only BackUp() if we're sure we've successfully called Next() at least
+ // once.
+ if (buffer_size_ > 0) {
+ 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() {
+ indent_ += " ";
+ }
+
+ // Reduces the current indent level by two spaces, or crashes if the indent
+ // level is zero.
+ void Outdent() {
+ if (indent_.empty()) {
+ GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
+ return;
+ }
+
+ indent_.resize(indent_.size() - 2);
+ }
+
+ // Print text to the output stream.
+ void Print(const string& str) {
+ Print(str.c_str());
+ }
+
+ // Print text to the output stream.
+ void Print(const char* text) {
+ int size = strlen(text);
+ int pos = 0; // The number of bytes we've written so far.
+
+ 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'.
+ 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);
+ }
+
+ // 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:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
+
+ void Write(const char* data, int size) {
+ if (failed_) return;
+ if (size == 0) return;
+
+ if (at_start_of_line_) {
+ // Insert an indent.
+ at_start_of_line_ = false;
+ Write(indent_.data(), indent_.size());
+ if (failed_) return;
+ }
+
+ while (size > buffer_size_) {
+ // Data exceeds space in the buffer. Copy what we can and request a
+ // new buffer.
+ memcpy(buffer_, data, 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;
+ }
+
+ io::ZeroCopyOutputStream* const output_;
+ char* buffer_;
+ int buffer_size_;
+ bool at_start_of_line_;
+ bool failed_;
+
+ string indent_;
+};
+
+// ===========================================================================
+
+TextFormat::Parser::Parser()
+ : error_collector_(NULL),
+ allow_partial_(false) {}
+
+TextFormat::Parser::~Parser() {}
+
+bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
+ Message* output) {
+ output->Clear();
+ return Merge(input, output);
+}
+
+bool TextFormat::Parser::ParseFromString(const string& input,
+ Message* output) {
+ io::ArrayInputStream input_stream(input.data(), input.size());
+ return Parse(&input_stream, output);
+}
+
+bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
+ Message* output) {
+ ParserImpl parser(input, error_collector_);
+ if (!parser.Parse(output)) return false;
+ if (!allow_partial_ && !output->IsInitialized()) {
+ vector<string> missing_fields;
+ output->FindInitializationErrors(&missing_fields);
+ parser.ReportError(-1, 0, "Message missing required fields: " +
+ JoinStrings(missing_fields, ", "));
+ return false;
+ }
+ return true;
+}
+
+bool TextFormat::Parser::MergeFromString(const string& input,
+ Message* output) {
+ io::ArrayInputStream input_stream(input.data(), input.size());
+ return Merge(&input_stream, 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(const string& input,
+ Message* output) {
+ return Parser().ParseFromString(input, output);
+}
+
+/* static */ bool TextFormat::MergeFromString(const string& input,
+ Message* output) {
+ return Parser().MergeFromString(input, output);
+}
+
+/* static */ bool TextFormat::PrintToString(const Message& message,
+ string* output) {
+ GOOGLE_DCHECK(output) << "output specified is NULL";
+
+ output->clear();
+ io::StringOutputStream output_stream(output);
+
+ bool result = Print(message, &output_stream);
+
+ return result;
+}
+
+/* static */ bool TextFormat::Print(const Message& message,
+ io::ZeroCopyOutputStream* output) {
+ TextGenerator generator(output);
+
+ Print(message.GetDescriptor(), message.GetReflection(), generator);
+
+ // Output false if the generator failed internally.
+ return !generator.failed();
+}
+
+/* static */ void TextFormat::Print(const Descriptor* descriptor,
+ const Message::Reflection* message,
+ TextGenerator& generator) {
+ vector<const FieldDescriptor*> fields;
+ message->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ PrintField(fields[i], message, generator);
+ }
+ PrintUnknownFields(message->GetUnknownFields(), generator);
+}
+
+/* static */ void TextFormat::PrintFieldValueToString(
+ const Message& message,
+ const FieldDescriptor* field,
+ int index,
+ string* output) {
+
+ GOOGLE_DCHECK(output) << "output specified is NULL";
+
+ output->clear();
+ io::StringOutputStream output_stream(output);
+ TextGenerator generator(&output_stream);
+
+ PrintFieldValue(message.GetReflection(), field, index, generator);
+}
+
+/* static */ void TextFormat::PrintField(const FieldDescriptor* field,
+ const Message::Reflection* message,
+ TextGenerator& generator) {
+ int count = 0;
+
+ if (field->is_repeated()) {
+ count = message->FieldSize(field);
+ } else if (message->HasField(field)) {
+ count = 1;
+ }
+
+ for (int j = 0; j < count; ++j) {
+ if (field->is_extension()) {
+ generator.Print("[");
+ // We special-case MessageSet elements for compatibility with proto1.
+ if (field->containing_type()->options().message_set_wire_format()
+ && field->type() == FieldDescriptor::TYPE_MESSAGE
+ && field->is_optional()
+ && field->extension_scope() == field->message_type()) {
+ generator.Print(field->message_type()->full_name());
+ } else {
+ generator.Print(field->full_name());
+ }
+ generator.Print("]");
+ } else {
+ if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ // Groups must be serialized with their original capitalization.
+ generator.Print(field->message_type()->name());
+ } else {
+ generator.Print(field->name());
+ }
+ }
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ generator.Print(" {\n");
+ generator.Indent();
+ } else {
+ generator.Print(": ");
+ }
+
+ // Write the field value.
+ int field_index = j;
+ if (!field->is_repeated()) {
+ field_index = -1;
+ }
+
+ PrintFieldValue(message, field, field_index, generator);
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ generator.Outdent();
+ generator.Print("}");
+ }
+
+ generator.Print("\n");
+ }
+}
+
+/* static */ void TextFormat::PrintFieldValue(
+ const Message::Reflection* reflection,
+ const FieldDescriptor* field,
+ int index,
+ TextGenerator& generator) {
+ GOOGLE_DCHECK(field->is_repeated() || (index == -1))
+ << "Index must be -1 for non-repeated fields";
+
+ switch (field->cpp_type()) {
+#define OUTPUT_FIELD(CPPTYPE, METHOD, TO_STRING) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ generator.Print(TO_STRING(field->is_repeated() ? \
+ reflection->GetRepeated##METHOD(field, index) : \
+ reflection->Get##METHOD(field))); \
+ break; \
+
+ OUTPUT_FIELD( INT32, Int32, SimpleItoa);
+ OUTPUT_FIELD( INT64, Int64, SimpleItoa);
+ OUTPUT_FIELD(UINT32, UInt32, SimpleItoa);
+ OUTPUT_FIELD(UINT64, UInt64, SimpleItoa);
+ OUTPUT_FIELD( FLOAT, Float, SimpleFtoa);
+ OUTPUT_FIELD(DOUBLE, Double, SimpleDtoa);
+#undef OUTPUT_FIELD
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ string scratch;
+ const string& value = field->is_repeated() ?
+ reflection->GetRepeatedStringReference(field, index, &scratch) :
+ reflection->GetStringReference(field, &scratch);
+
+ generator.Print("\"");
+ generator.Print(CEscape(value));
+ generator.Print("\"");
+
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_BOOL:
+ if (field->is_repeated()) {
+ generator.Print(reflection->GetRepeatedBool(field, index)
+ ? "true" : "false");
+ } else {
+ generator.Print(reflection->GetBool(field) ? "true" : "false");
+ }
+ break;
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ generator.Print(field->is_repeated() ?
+ reflection->GetRepeatedEnum(field, index)->name()
+ : reflection->GetEnum(field)->name());
+ break;
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ Print(field->message_type(),
+ field->is_repeated() ?
+ reflection->GetRepeatedMessage(field, index).GetReflection()
+ : reflection->GetMessage(field).GetReflection(), generator);
+ break;
+ }
+}
+
+// Prints an integer as hex with a fixed number of digits dependent on the
+// integer type.
+template<typename IntType>
+static string PaddedHex(IntType value) {
+ string result;
+ result.reserve(sizeof(value) * 2);
+ for (int i = sizeof(value) * 2 - 1; i >= 0; i--) {
+ result.push_back(int_to_hex_digit(value >> (i*4) & 0x0F));
+ }
+ return result;
+}
+
+/* static */ void TextFormat::PrintUnknownFields(
+ const UnknownFieldSet& unknown_fields, TextGenerator& generator) {
+ for (int i = 0; i < unknown_fields.field_count(); i++) {
+ const UnknownField& field = unknown_fields.field(i);
+ string field_number = SimpleItoa(field.number());
+
+ for (int j = 0; j < field.varint_size(); j++) {
+ generator.Print(field_number);
+ generator.Print(": ");
+ generator.Print(SimpleItoa(field.varint(j)));
+ generator.Print("\n");
+ }
+ for (int j = 0; j < field.fixed32_size(); j++) {
+ generator.Print(field_number);
+ generator.Print(": 0x");
+ char buffer[kFastToBufferSize];
+ generator.Print(FastHex32ToBuffer(field.fixed32(j), buffer));
+ generator.Print("\n");
+ }
+ for (int j = 0; j < field.fixed64_size(); j++) {
+ generator.Print(field_number);
+ generator.Print(": 0x");
+ char buffer[kFastToBufferSize];
+ generator.Print(FastHex64ToBuffer(field.fixed64(j), buffer));
+ generator.Print("\n");
+ }
+ for (int j = 0; j < field.length_delimited_size(); j++) {
+ generator.Print(field_number);
+ generator.Print(": \"");
+ generator.Print(CEscape(field.length_delimited(j)));
+ generator.Print("\"\n");
+ }
+ for (int j = 0; j < field.group_size(); j++) {
+ generator.Print(field_number);
+ generator.Print(" {\n");
+ generator.Indent();
+ PrintUnknownFields(field.group(j), generator);
+ generator.Outdent();
+ generator.Print("}\n");
+ }
+ }
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
new file mode 100644
index 00000000..df27710d
--- /dev/null
+++ b/src/google/protobuf/text_format.h
@@ -0,0 +1,143 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/message.h> // Message, Message::Reflection
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+ class ErrorCollector; // tokenizer.h
+}
+
+// This class implements protocol buffer text format. 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 LIBPROTOBUF_EXPORT TextFormat {
+ public:
+ // Outputs a textual representation of the given message to the given
+ // output stream.
+ static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
+ // Like Print(), but outputs directly to a string.
+ static bool PrintToString(const Message& message, 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,
+ string* output);
+
+ // Parses a text-format protocol message from the given input stream to
+ // the given message object. This function parses the format written
+ // by Print().
+ static bool Parse(io::ZeroCopyInputStream* input, Message* output);
+ // Like Parse(), but reads directly from a string.
+ static bool ParseFromString(const string& 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(const string& input, Message* output);
+
+ // For more control over parsing, use this class.
+ class LIBPROTOBUF_EXPORT Parser {
+ public:
+ Parser();
+ ~Parser();
+
+ // Like TextFormat::Parse().
+ bool Parse(io::ZeroCopyInputStream* input, Message* output);
+ // Like TextFormat::ParseFromString().
+ bool ParseFromString(const string& input, Message* output);
+ // Like TextFormat::Merge().
+ bool Merge(io::ZeroCopyInputStream* input, Message* output);
+ // Like TextFormat::MergeFromString().
+ bool MergeFromString(const string& input, Message* output);
+
+ // Set where to report parse errors. If NULL (the default), errors will
+ // be printed to stderr.
+ void RecordErrorsTo(io::ErrorCollector* error_collector) {
+ error_collector_ = error_collector;
+ }
+
+ // Normally parsing fails if, after parsing, output->IsInitialized()
+ // returns false. Call AllowPartialMessage(true) to skip this check.
+ void AllowPartialMessage(bool allow) {
+ allow_partial_ = allow;
+ }
+
+ private:
+ io::ErrorCollector* error_collector_;
+ bool allow_partial_;
+ };
+
+ private:
+ // 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 parse text
+ // representations (see text_format.cc for implementation).
+ class ParserImpl;
+
+ // Internal Print method, used for writing to the OutputStream via
+ // the TextGenerator class.
+ static void Print(const Descriptor* descriptor,
+ const Message::Reflection* message,
+ TextGenerator& generator);
+
+ // Print a single field.
+ static void PrintField(const FieldDescriptor* field,
+ const Message::Reflection* message,
+ TextGenerator& generator);
+
+ // Outputs a textual representation of the value of the field supplied on
+ // the message supplied or the default value if not set.
+ static void PrintFieldValue(const Message::Reflection* reflection,
+ const FieldDescriptor* field,
+ int index,
+ TextGenerator& generator);
+
+ // Print the fields in an UnknownFieldSet. They are printed by tag number
+ // only.
+ static void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+ TextGenerator& generator);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
+};
+
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..48c70763
--- /dev/null
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -0,0 +1,697 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: jschorr@google.com (Joseph Schorr)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits>
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+inline bool IsNaN(double value) {
+ // NaN is never equal to anything, even itself.
+ return value != value;
+}
+
+// A basic string with different escapable characters for testing.
+const string kEscapeTestString =
+ "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+ "slashes \\";
+
+// A representation of the above string with all the characters escaped.
+const string kEscapeTestStringEscaped =
+ "\"\\\"A string with \\' characters \\n and \\r newlines "
+ "and \\t tabs and \\001 slashes \\\\\"";
+
+class TextFormatTest : public testing::Test {
+ public:
+ static void SetUpTestCase() {
+ File::ReadFileToStringOrDie(
+ TestSourceDir()
+ + "/google/protobuf/testdata/text_format_unittest_data.txt",
+ &static_proto_debug_string_);
+ }
+
+ TextFormatTest() : proto_debug_string_(static_proto_debug_string_) {}
+
+ protected:
+ // Debug string read from text_format_unittest_data.txt.
+ const string proto_debug_string_;
+ unittest::TestAllTypes proto_;
+
+ private:
+ static string static_proto_debug_string_;
+};
+string TextFormatTest::static_proto_debug_string_;
+
+class TextFormatExtensionsTest : public testing::Test {
+ public:
+ static void SetUpTestCase() {
+ File::ReadFileToStringOrDie(
+ TestSourceDir()
+ + "/google/protobuf/testdata/"
+ "text_format_unittest_extensions_data.txt",
+ &static_proto_debug_string_);
+ }
+
+ TextFormatExtensionsTest()
+ : proto_debug_string_(static_proto_debug_string_) {}
+
+ protected:
+ // Debug string read from text_format_unittest_data.txt.
+ const string proto_debug_string_;
+ unittest::TestAllExtensions proto_;
+
+ private:
+ static string static_proto_debug_string_;
+};
+string TextFormatExtensionsTest::static_proto_debug_string_;
+
+
+TEST_F(TextFormatTest, Basic) {
+ TestUtil::SetAllFields(&proto_);
+ EXPECT_EQ(proto_debug_string_, proto_.DebugString());
+}
+
+TEST_F(TextFormatExtensionsTest, Extensions) {
+ TestUtil::SetAllExtensions(&proto_);
+ EXPECT_EQ(proto_debug_string_, proto_.DebugString());
+}
+
+TEST_F(TextFormatTest, StringEscape) {
+ // Set the string value to test.
+ proto_.set_optional_string(kEscapeTestString);
+
+ // Get the DebugString from the proto.
+ string debug_string = proto_.DebugString();
+
+ // Hardcode a correct value to test against.
+ string correct_string = "optional_string: "
+ + kEscapeTestStringEscaped
+ + "\n";
+
+ // Compare.
+ 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();
+ UnknownField* field5 = unknown_fields->AddField(5);
+
+ field5->add_varint(1);
+ field5->add_fixed32(2);
+ field5->add_fixed64(3);
+ field5->add_length_delimited("4");
+ field5->add_group()->AddField(10)->add_varint(5);
+
+ UnknownField* field8 = unknown_fields->AddField(8);
+ field8->add_varint(1);
+ field8->add_varint(2);
+ field8->add_varint(3);
+
+ EXPECT_EQ(
+ "5: 1\n"
+ "5: 0x00000002\n"
+ "5: 0x0000000000000003\n"
+ "5: \"4\"\n"
+ "5 {\n"
+ " 10: 5\n"
+ "}\n"
+ "8: 1\n"
+ "8: 2\n"
+ "8: 3\n",
+ message.DebugString());
+}
+
+TEST_F(TextFormatTest, ParseBasic) {
+ io::ArrayInputStream input_stream(proto_debug_string_.data(),
+ proto_debug_string_.size());
+ TextFormat::Parse(&input_stream, &proto_);
+ TestUtil::ExpectAllFieldsSet(proto_);
+}
+
+TEST_F(TextFormatExtensionsTest, ParseExtensions) {
+ io::ArrayInputStream input_stream(proto_debug_string_.data(),
+ proto_debug_string_.size());
+ TextFormat::Parse(&input_stream, &proto_);
+ TestUtil::ExpectAllExtensionsSet(proto_);
+}
+
+TEST_F(TextFormatTest, ParseStringEscape) {
+ // Create a parse string with escpaed characters in it.
+ 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, 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.
+ 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, Comments) {
+ // Test that comments are ignored.
+
+ 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.
+
+ 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 string RemoveRedundantZeros(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;
+
+ // Note: In C, a negative integer literal is actually the unary negation
+ // operator being applied to a positive integer literal, and
+ // 9223372036854775808 is outside the range of int64. However, it is not
+ // outside the range of uint64. Confusingly, this means that everything
+ // works if we make the literal unsigned, even though we are negating it.
+ message.add_repeated_int64(-GOOGLE_ULONGLONG(9223372036854775808));
+ message.add_repeated_uint64(GOOGLE_ULONGLONG(18446744073709551615));
+ 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_string(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", NULL));
+ // 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(
+ "repeated_int64: -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_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.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(
+ "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));
+ // Note: In C, a negative integer literal is actually the unary negation
+ // operator being applied to a positive integer literal, and 2147483648 is
+ // outside the range of int32. However, it is not outside the range of
+ // uint32. Confusingly, this means that everything works if we make the
+ // literal unsigned, even though we are negating it.
+ EXPECT_EQ(-2147483648u, message.repeated_int32(1));
+
+ ASSERT_EQ(2, message.repeated_int64_size());
+ EXPECT_EQ(-1, message.repeated_int64(0));
+ // Note: In C, a negative integer literal is actually the unary negation
+ // operator being applied to a positive integer literal, and
+ // 9223372036854775808 is outside the range of int64. However, it is not
+ // outside the range of uint64. Confusingly, this means that everything
+ // works if we make the literal unsigned, even though we are negating it.
+ EXPECT_EQ(-GOOGLE_ULONGLONG(9223372036854775808), 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(GOOGLE_ULONGLONG(18446744073709551615), message.repeated_uint64(0));
+ EXPECT_EQ(GOOGLE_ULONGLONG(9223372036854775808), 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), numeric_limits<double>::infinity());
+ EXPECT_EQ(message.repeated_double(8), numeric_limits<double>::infinity());
+ EXPECT_EQ(message.repeated_double(9), -numeric_limits<double>::infinity());
+ EXPECT_EQ(message.repeated_double(10), -numeric_limits<double>::infinity());
+ EXPECT_TRUE(IsNaN(message.repeated_double(11)));
+ EXPECT_TRUE(IsNaN(message.repeated_double(12)));
+
+ // 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(string("\000\001\a\b\f\n\r\t\v\\\'\"", 12),
+ message.repeated_string(0));
+}
+
+class TextFormatParserTest : public testing::Test {
+ protected:
+ void ExpectFailure(const string& input, const string& message, int line,
+ int col) {
+ unittest::TestAllTypes proto;
+ ExpectFailure(input, message, line, col, &proto);
+ }
+
+ void ExpectFailure(const string& input, const string& message, int line,
+ int col, Message* proto) {
+ TextFormat::Parser parser;
+ MockErrorCollector error_collector;
+ parser.RecordErrorsTo(&error_collector);
+ EXPECT_FALSE(parser.ParseFromString(input, proto));
+ EXPECT_EQ(SimpleItoa(line) + ":" + SimpleItoa(col) + ": " + message + "\n",
+ error_collector.text_);
+ }
+
+ // 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() {}
+
+ string text_;
+
+ // implements ErrorCollector -------------------------------------
+ void AddError(int line, int column, const string& message) {
+ strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
+ line + 1, column + 1, message);
+ }
+ };
+};
+
+TEST_F(TextFormatParserTest, InvalidToken) {
+ ExpectFailure("optional_bool: true\n-5\n", "Expected identifier.",
+ 2, 1);
+
+ ExpectFailure("optional_bool: true;\n", "Expected identifier.", 1, 20);
+ ExpectFailure("\"some string\"", "Expected identifier.", 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, InvalidFieldValues) {
+ // Invalid values for a double/float field.
+ ExpectFailure("optional_double: \"hello\"\n", "Expected double.", 1, 18);
+ ExpectFailure("optional_double: true\n", "Expected double.", 1, 18);
+ ExpectFailure("optional_double: !\n", "Expected double.", 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.", 1, 17);
+ ExpectFailure("optional_int32: true\n", "Expected integer.", 1, 17);
+ ExpectFailure("optional_int32: 4.5\n", "Expected integer.", 1, 17);
+ ExpectFailure("optional_int32: !\n", "Expected integer.", 1, 17);
+ ExpectFailure("optional_int32 {\n \n}\n", "Expected \":\", found \"{\".",
+ 1, 16);
+ ExpectFailure("optional_int32: 0x80000000\n",
+ "Integer out of range.", 1, 17);
+ ExpectFailure("optional_int32: -0x80000001\n",
+ "Integer out of range.", 1, 18);
+ ExpectFailure("optional_int64: 0x8000000000000000\n",
+ "Integer out of range.", 1, 17);
+ ExpectFailure("optional_int64: -0x8000000000000001\n",
+ "Integer out of range.", 1, 18);
+
+ // Invalid values for an unsigned integer field.
+ ExpectFailure("optional_uint64: \"hello\"\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64: true\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64: 4.5\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64: -5\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64: !\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64 {\n \n}\n", "Expected \":\", found \"{\".",
+ 1, 17);
+ ExpectFailure("optional_uint32: 0x100000000\n",
+ "Integer out of range.", 1, 18);
+ ExpectFailure("optional_uint64: 0x10000000000000000\n",
+ "Integer out of range.", 1, 18);
+
+ // Invalid values for a boolean field.
+ ExpectFailure("optional_bool: \"hello\"\n", "Expected identifier.", 1, 16);
+ ExpectFailure("optional_bool: 5\n", "Expected identifier.", 1, 16);
+ ExpectFailure("optional_bool: -7.5\n", "Expected identifier.", 1, 16);
+ ExpectFailure("optional_bool: !\n", "Expected identifier.", 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.", 1, 18);
+ ExpectFailure("optional_string: 5\n", "Expected string.", 1, 18);
+ ExpectFailure("optional_string: -7.5\n", "Expected string.", 1, 18);
+ ExpectFailure("optional_string: !\n", "Expected string.", 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 identifier.",
+ 1, 23);
+
+ ExpectFailure("optional_nested_enum: 5\n", "Expected identifier.", 1, 23);
+ ExpectFailure("optional_nested_enum: -7.5\n", "Expected identifier.", 1, 23);
+ ExpectFailure("optional_nested_enum: !\n", "Expected identifier.", 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, MessageDelimeters) {
+ // Non-matching delimeters.
+ ExpectFailure("OptionalGroup <\n \n}\n", "Expected \">\", found \"}\".",
+ 3, 1);
+
+ // Invalid delimeters.
+ ExpectFailure("OptionalGroup [\n \n]\n", "Expected \"{\", found \"[\".",
+ 1, 15);
+
+ // Unending message.
+ ExpectFailure("optional_nested_message {\n \nbb: 118\n",
+ "Expected identifier.",
+ 4, 1);
+}
+
+TEST_F(TextFormatParserTest, UnknownExtension) {
+ // Non-matching delimeters.
+ 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, PrintErrorsToStderr) {
+ vector<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]);
+}
+
+
+class TextFormatMessageSetTest : public testing::Test {
+ protected:
+ static const char proto_debug_string_[];
+};
+const char TextFormatMessageSetTest::proto_debug_string_[] =
+"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");
+ EXPECT_EQ(proto_debug_string_, proto.DebugString());
+}
+
+TEST_F(TextFormatMessageSetTest, Deserialize) {
+ protobuf_unittest::TestMessageSetContainer proto;
+ ASSERT_TRUE(TextFormat::ParseFromString(proto_debug_string_, &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.
+ vector<const FieldDescriptor*> descriptors;
+ proto.message_set().GetReflection()->ListFields(&descriptors);
+ EXPECT_EQ(2, descriptors.size());
+}
+
+} // namespace
+} // namespace protobuf
+
+} // namespace google
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
new file mode 100644
index 00000000..f65c4318
--- /dev/null
+++ b/src/google/protobuf/unittest.proto
@@ -0,0 +1,452 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+
+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;
+ }
+
+ // 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];
+
+ // 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];
+
+ // 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"];
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+ optional int32 c = 1;
+}
+
+enum ForeignEnum {
+ FOREIGN_FOO = 4;
+ FOREIGN_BAR = 5;
+ FOREIGN_BAZ = 6;
+}
+
+message 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];
+
+ // 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];
+
+ // 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"];
+}
+
+// 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;
+}
+
+message TestRequiredForeign {
+ optional TestRequired optional_message = 1;
+ repeated TestRequired repeated_message = 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;
+}
+
+// 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 {
+ optional TestMutualRecursionB bb = 1;
+}
+
+message TestMutualRecursionB {
+ optional TestMutualRecursionA a = 1;
+ optional int32 optional_int32 = 2;
+}
+
+// Test that groups have disjoint field numbers from their siblings and
+// parents. This is NOT possible in proto1; only proto2. When outputting
+// proto1, the dup fields should be dropped.
+message TestDupFieldNumber {
+ optional int32 a = 1;
+ optional group Foo = 2 { optional int32 a = 1; }
+ optional group Bar = 3 { optional int32 a = 1; }
+}
+
+
+// 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 {
+ 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;
+}
+
+
+extend TestFieldOrderings {
+ optional string my_extension_string = 50;
+ optional int32 my_extension_int = 5;
+}
+
+
+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];
+
+ // 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"];
+}
+
+// Test that RPC services work.
+message FooRequest {}
+message FooResponse {}
+
+service TestService {
+ rpc Foo(FooRequest) returns (FooResponse);
+ rpc Bar(BarRequest) returns (BarResponse);
+}
+
+
+message BarRequest {}
+message BarResponse {}
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 00000000..c600d9fc
--- /dev/null
+++ b/src/google/protobuf/unittest_embed_optimize_for.proto
@@ -0,0 +1,36 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+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_import.proto b/src/google/protobuf/unittest_import.proto
new file mode 100644
index 00000000..58ce42c3
--- /dev/null
+++ b/src/google/protobuf/unittest_import.proto
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+
+// 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;
+
+// Excercise 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.
+
+message ImportMessage {
+ optional int32 d = 1;
+}
+
+enum ImportEnum {
+ IMPORT_FOO = 7;
+ IMPORT_BAR = 8;
+ IMPORT_BAZ = 9;
+}
+
diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto
new file mode 100644
index 00000000..455086d2
--- /dev/null
+++ b/src/google/protobuf/unittest_mset.proto
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+package protobuf_unittest;
+
+option optimize_for = SPEED;
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+ option message_set_wire_format = true;
+ extensions 4 to max;
+}
+
+message TestMessageSetContainer {
+ optional TestMessageSet message_set = 1;
+}
+
+message TestMessageSetExtension1 {
+ extend TestMessageSet {
+ optional TestMessageSetExtension1 message_set_extension = 1545008;
+ }
+ optional int32 i = 15;
+}
+
+message TestMessageSetExtension2 {
+ extend TestMessageSet {
+ optional TestMessageSetExtension2 message_set_extension = 1547769;
+ }
+ optional string str = 25;
+}
+
+// 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_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto
new file mode 100644
index 00000000..6154e9c5
--- /dev/null
+++ b/src/google/protobuf/unittest_optimize_for.proto
@@ -0,0 +1,38 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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.
+
+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;
+ }
+}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
new file mode 100644
index 00000000..2f44901e
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -0,0 +1,112 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/stl_util-inl.h>
+
+namespace google {
+namespace protobuf {
+
+UnknownFieldSet::UnknownFieldSet()
+ : internal_(NULL) {}
+
+UnknownFieldSet::~UnknownFieldSet() {
+ if (internal_ != NULL) {
+ STLDeleteValues(&internal_->fields_);
+ delete internal_;
+ }
+}
+
+void UnknownFieldSet::Clear() {
+ if (internal_ == NULL) return;
+
+ if (internal_->fields_.size() > kMaxInactiveFields) {
+ STLDeleteValues(&internal_->fields_);
+ } else {
+ // Don't delete the UnknownField objects. Just remove them from the active
+ // set.
+ for (int i = 0; i < internal_->active_fields_.size(); i++) {
+ internal_->active_fields_[i]->Clear();
+ internal_->active_fields_[i]->index_ = -1;
+ }
+ }
+
+ internal_->active_fields_.clear();
+}
+
+void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
+ for (int i = 0; i < other.field_count(); i++) {
+ AddField(other.field(i).number())->MergeFrom(other.field(i));
+ }
+}
+
+const UnknownField* UnknownFieldSet::FindFieldByNumber(int number) const {
+ if (internal_ == NULL) return NULL;
+
+ map<int, UnknownField*>::iterator iter = internal_->fields_.find(number);
+ if (iter != internal_->fields_.end() && iter->second->index() != -1) {
+ return iter->second;
+ } else {
+ return NULL;
+ }
+}
+
+UnknownField* UnknownFieldSet::AddField(int number) {
+ if (internal_ == NULL) internal_ = new Internal;
+
+ UnknownField** map_slot = &internal_->fields_[number];
+ if (*map_slot == NULL) {
+ *map_slot = new UnknownField(number);
+ }
+
+ UnknownField* field = *map_slot;
+ if (field->index() == -1) {
+ field->index_ = internal_->active_fields_.size();
+ internal_->active_fields_.push_back(field);
+ }
+ return field;
+}
+
+UnknownField::UnknownField(int number)
+ : number_(number),
+ index_(-1) {
+}
+
+UnknownField::~UnknownField() {
+}
+
+void UnknownField::Clear() {
+ clear_varint();
+ clear_fixed32();
+ clear_fixed64();
+ clear_length_delimited();
+ clear_group();
+}
+
+void UnknownField::MergeFrom(const UnknownField& other) {
+ varint_ .MergeFrom(other.varint_ );
+ fixed32_ .MergeFrom(other.fixed32_ );
+ fixed64_ .MergeFrom(other.fixed64_ );
+ length_delimited_.MergeFrom(other.length_delimited_);
+ group_ .MergeFrom(other.group_ );
+}
+
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
new file mode 100644
index 00000000..42184621
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set.h
@@ -0,0 +1,322 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <map>
+#include <vector>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+
+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
+// Message::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 LIBPROTOBUF_EXPORT UnknownFieldSet {
+ public:
+ UnknownFieldSet();
+ ~UnknownFieldSet();
+
+ // Remove all fields.
+ void Clear();
+
+ // Is this set empty?
+ inline bool empty() const;
+
+ // Merge the contents of some other UnknownFieldSet with this one.
+ void MergeFrom(const UnknownFieldSet& other);
+
+ // 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 arbitrary order.
+ 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 arbitrary order.
+ inline UnknownField* mutable_field(int index);
+
+ // Find a field by field number. Returns NULL if not found.
+ const UnknownField* FindFieldByNumber(int number) const;
+
+ // Add a field by field number. If the field number already exists, returns
+ // the existing UnknownField.
+ UnknownField* AddField(int number);
+
+ private:
+ // "Active" fields are ones which have been added since the last time Clear()
+ // was called. Inactive fields are objects we are keeping around incase
+ // they become active again.
+
+ struct Internal {
+ // Contains all UnknownFields that have been allocated for this
+ // UnknownFieldSet, including ones not currently active. Keyed by
+ // field number. We intentionally try to reuse UnknownField objects for
+ // the same field number they were used for originally because this makes
+ // it more likely that the previously-allocated memory will have the right
+ // layout.
+ map<int, UnknownField*> fields_;
+
+ // Contains the fields from fields_ that are currently active.
+ vector<UnknownField*> active_fields_;
+ };
+
+ // We want an UnknownFieldSet to use no more space than a single pointer
+ // until the first field is added.
+ Internal* internal_;
+
+ // Don't keep more inactive fields than this.
+ static const int kMaxInactiveFields = 100;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
+};
+
+// Represents one field in an UnknownFieldSet.
+//
+// UnknownFiled's accessors are similar to those that would be produced by the
+// protocol compiler for the fields:
+// repeated uint64 varint;
+// repeated fixed32 fixed32;
+// repeated fixed64 fixed64;
+// repeated bytes length_delimited;
+// repeated UnknownFieldSet group;
+// (OK, so the last one isn't actually a valid field type but you get the
+// idea.)
+class LIBPROTOBUF_EXPORT UnknownField {
+ public:
+ ~UnknownField();
+
+ // Clears all fields.
+ void Clear();
+
+ // Merge the contents of some other UnknownField with this one. For each
+ // wire type, the values are simply concatenated.
+ void MergeFrom(const UnknownField& other);
+
+ // The field's tag number, as seen on the wire.
+ inline int number() const;
+
+ // The index of this UnknownField within the UknownFieldSet (e.g.
+ // set.field(field.index()) == field).
+ inline int index() const;
+
+ inline int varint_size () const;
+ inline int fixed32_size () const;
+ inline int fixed64_size () const;
+ inline int length_delimited_size() const;
+ inline int group_size () const;
+
+ inline uint64 varint (int index) const;
+ inline uint32 fixed32(int index) const;
+ inline uint64 fixed64(int index) const;
+ inline const string& length_delimited(int index) const;
+ inline const UnknownFieldSet& group(int index) const;
+
+ inline void set_varint (int index, uint64 value);
+ inline void set_fixed32(int index, uint32 value);
+ inline void set_fixed64(int index, uint64 value);
+ inline void set_length_delimited(int index, const string& value);
+ inline string* mutable_length_delimited(int index);
+ inline UnknownFieldSet* mutable_group(int index);
+
+ inline void add_varint (uint64 value);
+ inline void add_fixed32(uint32 value);
+ inline void add_fixed64(uint64 value);
+ inline void add_length_delimited(const string& value);
+ inline string* add_length_delimited();
+ inline UnknownFieldSet* add_group();
+
+ inline void clear_varint ();
+ inline void clear_fixed32();
+ inline void clear_fixed64();
+ inline void clear_length_delimited();
+ inline void clear_group();
+
+ inline const RepeatedField <uint64 >& varint () const;
+ inline const RepeatedField <uint32 >& fixed32 () const;
+ inline const RepeatedField <uint64 >& fixed64 () const;
+ inline const RepeatedPtrField<string >& length_delimited() const;
+ inline const RepeatedPtrField<UnknownFieldSet>& group () const;
+
+ inline RepeatedField <uint64 >* mutable_varint ();
+ inline RepeatedField <uint32 >* mutable_fixed32 ();
+ inline RepeatedField <uint64 >* mutable_fixed64 ();
+ inline RepeatedPtrField<string >* mutable_length_delimited();
+ inline RepeatedPtrField<UnknownFieldSet>* mutable_group ();
+
+ private:
+ friend class UnknownFieldSet;
+ UnknownField(int number);
+
+ int number_;
+ int index_;
+
+ RepeatedField <uint64 > varint_;
+ RepeatedField <uint32 > fixed32_;
+ RepeatedField <uint64 > fixed64_;
+ RepeatedPtrField<string > length_delimited_;
+ RepeatedPtrField<UnknownFieldSet> group_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownField);
+};
+
+// ===================================================================
+// inline implementations
+
+inline bool UnknownFieldSet::empty() const {
+ return internal_ == NULL || internal_->active_fields_.empty();
+}
+
+inline int UnknownFieldSet::field_count() const {
+ return (internal_ == NULL) ? 0 : internal_->active_fields_.size();
+}
+inline const UnknownField& UnknownFieldSet::field(int index) const {
+ return *(internal_->active_fields_[index]);
+}
+inline UnknownField* UnknownFieldSet::mutable_field(int index) {
+ return internal_->active_fields_[index];
+}
+
+inline int UnknownField::number() const { return number_; }
+inline int UnknownField::index () const { return index_; }
+
+inline int UnknownField::varint_size () const {return varint_.size();}
+inline int UnknownField::fixed32_size () const {return fixed32_.size();}
+inline int UnknownField::fixed64_size () const {return fixed64_.size();}
+inline int UnknownField::length_delimited_size() const {
+ return length_delimited_.size();
+}
+inline int UnknownField::group_size () const {return group_.size();}
+
+inline uint64 UnknownField::varint (int index) const {
+ return varint_.Get(index);
+}
+inline uint32 UnknownField::fixed32(int index) const {
+ return fixed32_.Get(index);
+}
+inline uint64 UnknownField::fixed64(int index) const {
+ return fixed64_.Get(index);
+}
+inline const string& UnknownField::length_delimited(int index) const {
+ return length_delimited_.Get(index);
+}
+inline const UnknownFieldSet& UnknownField::group(int index) const {
+ return group_.Get(index);
+}
+
+inline void UnknownField::set_varint (int index, uint64 value) {
+ varint_.Set(index, value);
+}
+inline void UnknownField::set_fixed32(int index, uint32 value) {
+ fixed32_.Set(index, value);
+}
+inline void UnknownField::set_fixed64(int index, uint64 value) {
+ fixed64_.Set(index, value);
+}
+inline void UnknownField::set_length_delimited(int index, const string& value) {
+ length_delimited_.Mutable(index)->assign(value);
+}
+inline string* UnknownField::mutable_length_delimited(int index) {
+ return length_delimited_.Mutable(index);
+}
+inline UnknownFieldSet* UnknownField::mutable_group(int index) {
+ return group_.Mutable(index);
+}
+
+inline void UnknownField::add_varint (uint64 value) {
+ varint_.Add(value);
+}
+inline void UnknownField::add_fixed32(uint32 value) {
+ fixed32_.Add(value);
+}
+inline void UnknownField::add_fixed64(uint64 value) {
+ fixed64_.Add(value);
+}
+inline void UnknownField::add_length_delimited(const string& value) {
+ length_delimited_.Add()->assign(value);
+}
+inline string* UnknownField::add_length_delimited() {
+ return length_delimited_.Add();
+}
+inline UnknownFieldSet* UnknownField::add_group() {
+ return group_.Add();
+}
+
+inline void UnknownField::clear_varint () { varint_.Clear(); }
+inline void UnknownField::clear_fixed32() { varint_.Clear(); }
+inline void UnknownField::clear_fixed64() { varint_.Clear(); }
+inline void UnknownField::clear_length_delimited() {
+ length_delimited_.Clear();
+}
+inline void UnknownField::clear_group() { group_.Clear(); }
+
+inline const RepeatedField<uint64>& UnknownField::varint () const {
+ return varint_;
+}
+inline const RepeatedField<uint32>& UnknownField::fixed32() const {
+ return fixed32_;
+}
+inline const RepeatedField<uint64>& UnknownField::fixed64() const {
+ return fixed64_;
+}
+inline const RepeatedPtrField<string>& UnknownField::length_delimited() const {
+ return length_delimited_;
+}
+inline const RepeatedPtrField<UnknownFieldSet>& UnknownField::group() const {
+ return group_;
+}
+
+inline RepeatedField<uint64>* UnknownField::mutable_varint () {
+ return &varint_;
+}
+inline RepeatedField<uint32>* UnknownField::mutable_fixed32() {
+ return &fixed32_;
+}
+inline RepeatedField<uint64>* UnknownField::mutable_fixed64() {
+ return &fixed64_;
+}
+inline RepeatedPtrField<string>* UnknownField::mutable_length_delimited() {
+ return &length_delimited_;
+}
+inline RepeatedPtrField<UnknownFieldSet>* UnknownField::mutable_group() {
+ return &group_;
+}
+
+} // namespace protobuf
+
+} // namespace google
+#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 00000000..39b005f4
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -0,0 +1,424 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+using internal::WireFormat;
+
+namespace {
+
+class UnknownFieldSetTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ 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 string& name) {
+ const FieldDescriptor* field = descriptor_->FindFieldByName(name);
+ if (field == NULL) return NULL;
+ return unknown_fields_->FindFieldByNumber(field->number());
+ }
+
+ // 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.
+ 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);
+ UnknownField* bizarro_field =
+ bizarro_unknown_fields->AddField(unknown_field.number());
+ if (unknown_field.varint_size() == 0) {
+ bizarro_field->add_varint(1);
+ } else {
+ bizarro_field->add_fixed32(1);
+ }
+ }
+
+ string data;
+ EXPECT_TRUE(bizarro_message.SerializeToString(&data));
+ return data;
+ }
+
+ const Descriptor* descriptor_;
+ unittest::TestAllTypes all_fields_;
+ 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_;
+};
+
+TEST_F(UnknownFieldSetTest, Index) {
+ for (int i = 0; i < unknown_fields_->field_count(); i++) {
+ EXPECT_EQ(i, unknown_fields_->field(i).index());
+ }
+}
+
+TEST_F(UnknownFieldSetTest, FindFieldByNumber) {
+ // All fields of TestAllTypes should be present. Fields that are not valid
+ // field numbers of TestAllTypes should NOT be present.
+
+ for (int i = 0; i < 1000; i++) {
+ if (descriptor_->FindFieldByNumber(i) == NULL) {
+ EXPECT_TRUE(unknown_fields_->FindFieldByNumber(i) == NULL);
+ } else {
+ EXPECT_TRUE(unknown_fields_->FindFieldByNumber(i) != NULL);
+ }
+ }
+}
+
+TEST_F(UnknownFieldSetTest, Varint) {
+ const UnknownField* field = GetField("optional_int32");
+ ASSERT_TRUE(field != NULL);
+
+ ASSERT_EQ(1, field->varint_size());
+ EXPECT_EQ(all_fields_.optional_int32(), field->varint(0));
+}
+
+TEST_F(UnknownFieldSetTest, Fixed32) {
+ const UnknownField* field = GetField("optional_fixed32");
+ ASSERT_TRUE(field != NULL);
+
+ ASSERT_EQ(1, field->fixed32_size());
+ EXPECT_EQ(all_fields_.optional_fixed32(), field->fixed32(0));
+}
+
+TEST_F(UnknownFieldSetTest, Fixed64) {
+ const UnknownField* field = GetField("optional_fixed64");
+ ASSERT_TRUE(field != NULL);
+
+ ASSERT_EQ(1, field->fixed64_size());
+ EXPECT_EQ(all_fields_.optional_fixed64(), field->fixed64(0));
+}
+
+TEST_F(UnknownFieldSetTest, LengthDelimited) {
+ const UnknownField* field = GetField("optional_string");
+ ASSERT_TRUE(field != NULL);
+
+ ASSERT_EQ(1, field->length_delimited_size());
+ EXPECT_EQ(all_fields_.optional_string(), field->length_delimited(0));
+}
+
+TEST_F(UnknownFieldSetTest, Group) {
+ const UnknownField* field = GetField("optionalgroup");
+ ASSERT_TRUE(field != NULL);
+
+ ASSERT_EQ(1, field->group_size());
+ EXPECT_EQ(1, field->group(0).field_count());
+
+ const UnknownField& nested_field = field->group(0).field(0);
+ const FieldDescriptor* nested_field_descriptor =
+ unittest::TestAllTypes::OptionalGroup::descriptor()->FindFieldByName("a");
+ ASSERT_TRUE(nested_field_descriptor != NULL);
+
+ EXPECT_EQ(nested_field_descriptor->number(), nested_field.number());
+ EXPECT_EQ(all_fields_.optionalgroup().a(), nested_field.varint(0));
+}
+
+TEST_F(UnknownFieldSetTest, Serialize) {
+ // Check that serializing the UnknownFieldSet produces the original data
+ // again.
+
+ 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(message.GetDescriptor(), &input,
+ message.GetReflection()));
+
+ EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, SerializeViaReflection) {
+ // Make sure fields are properly written from the UnknownFieldSet when
+ // serializing via reflection.
+
+ string data;
+
+ {
+ io::StringOutputStream raw_output(&data);
+ io::CodedOutputStream output(&raw_output);
+ int size = WireFormat::ByteSize(empty_message_.GetDescriptor(),
+ empty_message_.GetReflection());
+ ASSERT_TRUE(
+ WireFormat::SerializeWithCachedSizes(empty_message_.GetDescriptor(),
+ empty_message_.GetReflection(),
+ size, &output));
+ }
+
+ // 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, MergeFrom) {
+ unittest::TestEmptyMessage source, destination;
+
+ destination.mutable_unknown_fields()->AddField(1)->add_varint(1);
+ destination.mutable_unknown_fields()->AddField(3)->add_varint(2);
+ source.mutable_unknown_fields()->AddField(2)->add_varint(3);
+ source.mutable_unknown_fields()->AddField(3)->add_varint(4);
+
+ destination.MergeFrom(source);
+
+ EXPECT_EQ(
+ // Note: The ordering of fields here depends on the ordering of adds
+ // and merging, above.
+ "1: 1\n"
+ "3: 2\n"
+ "3: 4\n"
+ "2: 3\n",
+ destination.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, Clear) {
+ // Get a pointer to a contained field object.
+ const UnknownField* field = GetField("optional_int32");
+ ASSERT_TRUE(field != NULL);
+ ASSERT_EQ(1, field->varint_size());
+ int number = field->number();
+
+ // Clear the set.
+ empty_message_.Clear();
+ EXPECT_EQ(0, unknown_fields_->field_count());
+
+ // If we add that field again we should get the same object.
+ ASSERT_EQ(field, unknown_fields_->AddField(number));
+
+ // But it should be cleared.
+ EXPECT_EQ(0, field->varint_size());
+}
+
+TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) {
+ // Test mixing known and unknown fields when parsing.
+
+ unittest::TestEmptyMessage source;
+ source.mutable_unknown_fields()->AddField(123456)->add_varint(654321);
+ 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(1, destination.unknown_fields().field(0).varint_size());
+ EXPECT_EQ(654321, destination.unknown_fields().field(0).varint(0));
+}
+
+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;
+ 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;
+ string bizarro_data = GetBizarroData();
+ io::ArrayInputStream raw_input(bizarro_data.data(), bizarro_data.size());
+ io::CodedInputStream input(&raw_input);
+ ASSERT_TRUE(WireFormat::ParseAndMergePartial(
+ all_types_message.GetDescriptor(), &input,
+ all_types_message.GetReflection()));
+ 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(message.GetDescriptor(), &input,
+ message.GetReflection()));
+
+ 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;
+ 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::TestAllTypes;
+ using unittest::TestAllExtensions;
+ 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 != NULL);
+ ASSERT_TRUE(repeated_field != NULL);
+
+ string data;
+
+ {
+ TestEmptyMessage empty_message;
+ UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields();
+ UnknownField* singular_unknown_field =
+ unknown_fields->AddField(singular_field->number());
+ singular_unknown_field->add_varint(TestAllTypes::BAR);
+ singular_unknown_field->add_varint(5); // not valid
+ UnknownField* repeated_unknown_field =
+ unknown_fields->AddField(repeated_field->number());
+ repeated_unknown_field->add_varint(TestAllTypes::FOO);
+ repeated_unknown_field->add_varint(4); // not valid
+ repeated_unknown_field->add_varint(TestAllTypes::BAZ);
+ repeated_unknown_field->add_varint(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(2, unknown_fields.field_count());
+
+ const UnknownField& singular_unknown_field = unknown_fields.field(0);
+ ASSERT_EQ(singular_field->number(), singular_unknown_field.number());
+ ASSERT_EQ(1, singular_unknown_field.varint_size());
+ EXPECT_EQ(5, singular_unknown_field.varint(0));
+
+ const UnknownField& repeated_unknown_field = unknown_fields.field(1);
+ ASSERT_EQ(repeated_field->number(), repeated_unknown_field.number());
+ ASSERT_EQ(2, repeated_unknown_field.varint_size());
+ EXPECT_EQ(4, repeated_unknown_field.varint(0));
+ EXPECT_EQ(6, repeated_unknown_field.varint(1));
+ }
+
+ {
+ 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(2, unknown_fields.field_count());
+
+ const UnknownField& singular_unknown_field = unknown_fields.field(0);
+ ASSERT_EQ(singular_field->number(), singular_unknown_field.number());
+ ASSERT_EQ(1, singular_unknown_field.varint_size());
+ EXPECT_EQ(5, singular_unknown_field.varint(0));
+
+ const UnknownField& repeated_unknown_field = unknown_fields.field(1);
+ ASSERT_EQ(repeated_field->number(), repeated_unknown_field.number());
+ ASSERT_EQ(2, repeated_unknown_field.varint_size());
+ EXPECT_EQ(4, repeated_unknown_field.varint(0));
+ EXPECT_EQ(6, repeated_unknown_field.varint(1));
+ }
+}
+
+} // 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 00000000..77e9c74b
--- /dev/null
+++ b/src/google/protobuf/wire_format.cc
@@ -0,0 +1,801 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <stack>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/wire_format_inl.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/unknown_field_set.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+// This function turns out to be convenient when using some macros later.
+inline int GetEnumNumber(const EnumValueDescriptor* descriptor) {
+ return descriptor->number();
+}
+
+// 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;
+// }
+// }
+const int kMessageSetItemStartTag =
+ GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormat::WIRETYPE_START_GROUP);
+const int kMessageSetItemEndTag =
+ GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormat::WIRETYPE_END_GROUP);
+const int kMessageSetTypeIdTag =
+ GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(2, WireFormat::WIRETYPE_VARINT);
+const int kMessageSetMessageTag =
+ GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(3, WireFormat::WIRETYPE_LENGTH_DELIMITED);
+
+// Byte size of all tags of a MessageSet::Item combined.
+static const int kMessageSetItemTagsSize =
+ io::CodedOutputStream::VarintSize32(kMessageSetItemStartTag) +
+ io::CodedOutputStream::VarintSize32(kMessageSetItemEndTag) +
+ io::CodedOutputStream::VarintSize32(kMessageSetTypeIdTag) +
+ io::CodedOutputStream::VarintSize32(kMessageSetMessageTag);
+
+} // anonymous namespace
+
+const WireFormat::WireType
+WireFormat::kWireTypeForFieldType[FieldDescriptor::MAX_TYPE + 1] = {
+ static_cast<WireFormat::WireType>(-1), // invalid
+ WIRETYPE_FIXED64, // TYPE_DOUBLE
+ WIRETYPE_FIXED32, // TYPE_FLOAT
+ WIRETYPE_VARINT, // TYPE_INT64
+ WIRETYPE_VARINT, // TYPE_UINT64
+ WIRETYPE_VARINT, // TYPE_INT32
+ WIRETYPE_FIXED64, // TYPE_FIXED64
+ WIRETYPE_FIXED32, // TYPE_FIXED32
+ WIRETYPE_VARINT, // TYPE_BOOL
+ WIRETYPE_LENGTH_DELIMITED, // TYPE_STRING
+ WIRETYPE_START_GROUP, // TYPE_GROUP
+ WIRETYPE_LENGTH_DELIMITED, // TYPE_MESSAGE
+ WIRETYPE_LENGTH_DELIMITED, // TYPE_BYTES
+ WIRETYPE_VARINT, // TYPE_UINT32
+ WIRETYPE_VARINT, // TYPE_ENUM
+ WIRETYPE_FIXED32, // TYPE_SFIXED32
+ WIRETYPE_FIXED64, // TYPE_SFIXED64
+ WIRETYPE_VARINT, // TYPE_SINT32
+ WIRETYPE_VARINT, // TYPE_SINT64
+};
+
+// ===================================================================
+
+bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag,
+ UnknownFieldSet* unknown_fields) {
+ UnknownField* field = (unknown_fields == NULL) ? NULL :
+ unknown_fields->AddField(GetTagFieldNumber(tag));
+
+ switch (GetTagWireType(tag)) {
+ case WIRETYPE_VARINT: {
+ uint64 value;
+ if (!input->ReadVarint64(&value)) return false;
+ if (field != NULL) field->add_varint(value);
+ return true;
+ }
+ case WIRETYPE_FIXED64: {
+ uint64 value;
+ if (!input->ReadLittleEndian64(&value)) return false;
+ if (field != NULL) field->add_fixed64(value);
+ return true;
+ }
+ case WIRETYPE_LENGTH_DELIMITED: {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (field == NULL) {
+ if (!input->Skip(length)) return false;
+ } else {
+ input->ReadString(field->add_length_delimited(), length);
+ }
+ return true;
+ }
+ case WIRETYPE_START_GROUP: {
+ if (!input->IncrementRecursionDepth()) return false;
+ if (!SkipMessage(input, (field == NULL) ? NULL : field->add_group())) {
+ return false;
+ }
+ input->DecrementRecursionDepth();
+ // Check that the ending tag matched the starting tag.
+ if (!input->LastTagWas(
+ MakeTag(GetTagFieldNumber(tag), WIRETYPE_END_GROUP))) {
+ return false;
+ }
+ return true;
+ }
+ case WIRETYPE_END_GROUP: {
+ return false;
+ }
+ case WIRETYPE_FIXED32: {
+ uint32 value;
+ if (!input->ReadLittleEndian32(&value)) return false;
+ if (field != NULL) field->add_fixed32(value);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+bool WireFormat::SkipMessage(io::CodedInputStream* input,
+ UnknownFieldSet* unknown_fields) {
+ while(true) {
+ uint32 tag = input->ReadTag();
+ if (tag == 0) {
+ // End of input. This is a valid place to end, so return true.
+ return true;
+ }
+
+ WireType wire_type = GetTagWireType(tag);
+
+ if (wire_type == WIRETYPE_END_GROUP) {
+ // Must be the end of the message.
+ return true;
+ }
+
+ if (!SkipField(input, tag, unknown_fields)) return false;
+ }
+}
+
+bool WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
+ io::CodedOutputStream* output) {
+ for (int i = 0; i < unknown_fields.field_count(); i++) {
+ const UnknownField& field = unknown_fields.field(i);
+
+#define DO(EXPRESSION) if (!(EXPRESSION)) return false
+ for (int j = 0; j < field.varint_size(); j++) {
+ DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_VARINT)));
+ DO(output->WriteVarint64(field.varint(j)));
+ }
+ for (int j = 0; j < field.fixed32_size(); j++) {
+ DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED32)));
+ DO(output->WriteLittleEndian32(field.fixed32(j)));
+ }
+ for (int j = 0; j < field.fixed64_size(); j++) {
+ DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED64)));
+ DO(output->WriteLittleEndian64(field.fixed64(j)));
+ }
+ for (int j = 0; j < field.length_delimited_size(); j++) {
+ DO(output->WriteVarint32(
+ MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED)));
+ DO(output->WriteVarint32(field.length_delimited(j).size()));
+ DO(output->WriteString(field.length_delimited(j)));
+ }
+ for (int j = 0; j < field.group_size(); j++) {
+ DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_START_GROUP)));
+ DO(SerializeUnknownFields(field.group(j), output));
+ DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_END_GROUP)));
+ }
+#undef DO
+ }
+
+ return true;
+}
+
+bool WireFormat::SerializeUnknownMessageSetItems(
+ const UnknownFieldSet& unknown_fields,
+ io::CodedOutputStream* output) {
+ for (int i = 0; i < unknown_fields.field_count(); i++) {
+ const UnknownField& field = unknown_fields.field(i);
+
+#define DO(EXPRESSION) if (!(EXPRESSION)) return false
+ // The only unknown fields that are allowed to exist in a MessageSet are
+ // messages, which are length-delimited.
+ for (int j = 0; j < field.length_delimited_size(); j++) {
+ const string& data = field.length_delimited(j);
+
+ // Start group.
+ DO(output->WriteVarint32(kMessageSetItemStartTag));
+
+ // Write type ID.
+ DO(output->WriteVarint32(kMessageSetTypeIdTag));
+ DO(output->WriteVarint32(field.number()));
+
+ // Write message.
+ DO(output->WriteVarint32(kMessageSetMessageTag));
+ DO(output->WriteVarint32(data.size()));
+ DO(output->WriteString(data));
+
+ // End group.
+ DO(output->WriteVarint32(kMessageSetItemEndTag));
+ }
+#undef DO
+ }
+
+ return true;
+}
+
+int WireFormat::ComputeUnknownFieldsSize(
+ const UnknownFieldSet& unknown_fields) {
+ int size = 0;
+ for (int i = 0; i < unknown_fields.field_count(); i++) {
+ const UnknownField& field = unknown_fields.field(i);
+
+ for (int j = 0; j < field.varint_size(); j++) {
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_VARINT));
+ size += io::CodedOutputStream::VarintSize64(field.varint(j));
+ }
+ for (int j = 0; j < field.fixed32_size(); j++) {
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_FIXED32));
+ size += sizeof(int32);
+ }
+ for (int j = 0; j < field.fixed64_size(); j++) {
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_FIXED64));
+ size += sizeof(int64);
+ }
+ for (int j = 0; j < field.length_delimited_size(); j++) {
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED));
+ size += io::CodedOutputStream::VarintSize32(
+ field.length_delimited(j).size());
+ size += field.length_delimited(j).size();
+ }
+ for (int j = 0; j < field.group_size(); j++) {
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_START_GROUP));
+ size += ComputeUnknownFieldsSize(field.group(j));
+ size += io::CodedOutputStream::VarintSize32(
+ MakeTag(field.number(), WIRETYPE_END_GROUP));
+ }
+ }
+
+ return size;
+}
+
+int WireFormat::ComputeUnknownMessageSetItemsSize(
+ const UnknownFieldSet& unknown_fields) {
+ int 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.
+ for (int j = 0; j < field.length_delimited_size(); j++) {
+ size += kMessageSetItemTagsSize;
+ size += io::CodedOutputStream::VarintSize32(field.number());
+ size += io::CodedOutputStream::VarintSize32(
+ field.length_delimited(j).size());
+ size += field.length_delimited(j).size();
+ }
+ }
+
+ return size;
+}
+
+// ===================================================================
+
+bool WireFormat::ParseAndMergePartial(const Descriptor* descriptor,
+ io::CodedInputStream* input,
+ Message::Reflection* message_reflection) {
+ while(true) {
+ uint32 tag = input->ReadTag();
+ if (tag == 0) {
+ // End of input. This is a valid place to end, so return true.
+ return true;
+ }
+
+ if (GetTagWireType(tag) == WIRETYPE_END_GROUP) {
+ // Must be the end of the message.
+ return true;
+ }
+
+ const FieldDescriptor* field = NULL;
+
+ if (descriptor != NULL) {
+ int field_number = GetTagFieldNumber(tag);
+ field = descriptor->FindFieldByNumber(field_number);
+
+ // If that failed, check if the field is an extension.
+ if (field == NULL && descriptor->IsExtensionNumber(field_number)) {
+ field = message_reflection->FindKnownExtensionByNumber(field_number);
+ }
+
+ // If that failed, but we're a MessageSet, and this is the tag for a
+ // MessageSet item, then parse that.
+ if (field == NULL &&
+ descriptor->options().message_set_wire_format() &&
+ tag == kMessageSetItemStartTag) {
+ if (!ParseAndMergeMessageSetItem(input, message_reflection)) {
+ return false;
+ }
+ continue; // Skip ParseAndMergeField(); already taken care of.
+ }
+ }
+
+ if (!ParseAndMergeField(tag, field, message_reflection, input)) {
+ return false;
+ }
+ }
+}
+
+bool WireFormat::ParseAndMergeField(
+ uint32 tag,
+ const FieldDescriptor* field, // May be NULL for unknown
+ Message::Reflection* message_reflection,
+ io::CodedInputStream* input) {
+ if (field == NULL ||
+ GetTagWireType(tag) != WireTypeForFieldType(field->type())) {
+ // 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.
+ return SkipField(input, tag, message_reflection->MutableUnknownFields());
+ }
+
+ switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: { \
+ CPPTYPE value; \
+ if (!Read##TYPE_METHOD(input, &value)) return false; \
+ if (field->is_repeated()) { \
+ message_reflection->Add##CPPTYPE_METHOD(field, value); \
+ } else { \
+ message_reflection->Set##CPPTYPE_METHOD(field, value); \
+ } \
+ break; \
+ }
+
+ HANDLE_TYPE( INT32, Int32, int32, Int32)
+ HANDLE_TYPE( INT64, Int64, int64, Int64)
+ HANDLE_TYPE(SINT32, SInt32, int32, Int32)
+ HANDLE_TYPE(SINT64, SInt64, int64, Int64)
+ HANDLE_TYPE(UINT32, UInt32, uint32, UInt32)
+ HANDLE_TYPE(UINT64, UInt64, uint64, UInt64)
+
+ HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32)
+ HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64)
+ HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32)
+ HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64)
+
+ HANDLE_TYPE(FLOAT , Float , float , Float )
+ HANDLE_TYPE(DOUBLE, Double, double, Double)
+
+ HANDLE_TYPE(BOOL, Bool, bool, Bool)
+
+ HANDLE_TYPE(STRING, String, string, String)
+ HANDLE_TYPE(BYTES, Bytes, string, String)
+
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::TYPE_ENUM: {
+ int value;
+ if (!ReadEnum(input, &value)) return false;
+ const EnumValueDescriptor* enum_value =
+ field->enum_type()->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ if (field->is_repeated()) {
+ message_reflection->AddEnum(field, enum_value);
+ } else {
+ message_reflection->SetEnum(field, enum_value);
+ }
+ } else {
+ // The enum value is not one of the known values. Add it to the
+ // UnknownFieldSet.
+ int64 sign_extended_value = static_cast<int64>(value);
+ message_reflection->MutableUnknownFields()
+ ->AddField(GetTagFieldNumber(tag))
+ ->add_varint(sign_extended_value);
+ }
+ break;
+ }
+
+
+ case FieldDescriptor::TYPE_GROUP: {
+ Message* sub_message;
+ if (field->is_repeated()) {
+ sub_message = message_reflection->AddMessage(field);
+ } else {
+ sub_message = message_reflection->MutableMessage(field);
+ }
+
+ if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message)) return false;
+ break;
+ }
+
+ case FieldDescriptor::TYPE_MESSAGE: {
+ Message* sub_message;
+ if (field->is_repeated()) {
+ sub_message = message_reflection->AddMessage(field);
+ } else {
+ sub_message = message_reflection->MutableMessage(field);
+ }
+
+ if (!ReadMessage(input, sub_message)) return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool WireFormat::ParseAndMergeMessageSetItem(
+ io::CodedInputStream* input,
+ Message::Reflection* message_reflection) {
+ // This method parses a group which should contain two fields:
+ // required int32 type_id = 2;
+ // required data message = 3;
+
+ // Once we see a type_id, we'll construct a fake tag for this extension
+ // which is the tag it would have had under the proto2 extensions wire
+ // format.
+ uint32 fake_tag = 0;
+
+ // Once we see a type_id, we'll look up the FieldDescriptor for the
+ // extension.
+ const FieldDescriptor* field = NULL;
+
+ // If we see message data before the type_id, we'll append it to this so
+ // we can parse it later. This will probably never happen in practice,
+ // as no MessageSet encoder I know of writes the message before the type ID.
+ // But, it's technically valid so we should allow it.
+ // TODO(kenton): Use a Cord instead? Do I care?
+ string message_data;
+
+ while (true) {
+ uint32 tag = input->ReadTag();
+ if (tag == 0) return false;
+
+ switch (tag) {
+ case kMessageSetTypeIdTag: {
+ uint32 type_id;
+ if (!input->ReadVarint32(&type_id)) return false;
+ fake_tag = MakeTag(type_id, WIRETYPE_LENGTH_DELIMITED);
+ field = message_reflection->FindKnownExtensionByNumber(type_id);
+
+ if (!message_data.empty()) {
+ // We saw some message data before the type_id. Have to parse it
+ // now.
+ io::ArrayInputStream raw_input(message_data.data(),
+ message_data.size());
+ io::CodedInputStream sub_input(&raw_input);
+ if (!ParseAndMergeField(fake_tag, field, message_reflection,
+ &sub_input)) {
+ return false;
+ }
+ message_data.clear();
+ }
+
+ break;
+ }
+
+ case kMessageSetMessageTag: {
+ if (fake_tag == 0) {
+ // We haven't seen a type_id yet. Append this data to message_data.
+ string temp;
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (!input->ReadString(&temp, length)) return false;
+ message_data.append(temp);
+ } else {
+ // Already saw type_id, so we can parse this directly.
+ if (!ParseAndMergeField(fake_tag, field, message_reflection, input)) {
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case kMessageSetItemEndTag: {
+ return true;
+ }
+
+ default: {
+ if (!SkipField(input, tag, NULL)) return false;
+ }
+ }
+ }
+}
+
+// ===================================================================
+
+bool WireFormat::SerializeWithCachedSizes(
+ const Descriptor* descriptor,
+ const Message::Reflection* message_reflection,
+ int size, io::CodedOutputStream* output) {
+ int expected_endpoint = output->ByteCount() + size;
+
+ vector<const FieldDescriptor*> fields;
+ message_reflection->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ if (!SerializeFieldWithCachedSizes(fields[i], message_reflection, output)) {
+ return false;
+ }
+ }
+
+ if (descriptor->options().message_set_wire_format()) {
+ if (!SerializeUnknownMessageSetItems(
+ message_reflection->GetUnknownFields(), output)) {
+ return false;
+ }
+ } else {
+ if (!SerializeUnknownFields(
+ message_reflection->GetUnknownFields(), output)) {
+ return false;
+ }
+ }
+
+ 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?";
+
+ return true;
+}
+
+bool WireFormat::SerializeFieldWithCachedSizes(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection,
+ io::CodedOutputStream* output) {
+ if (field->is_extension() &&
+ field->containing_type()->options().message_set_wire_format() &&
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !field->is_repeated()) {
+ return SerializeMessageSetItemWithCachedSizes(
+ field, message_reflection, output);
+ }
+
+ int count = 0;
+
+ if (field->is_repeated()) {
+ count = message_reflection->FieldSize(field);
+ } else if (message_reflection->HasField(field)) {
+ count = 1;
+ }
+
+ for (int j = 0; j < count; j++) {
+ switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: \
+ if (!Write##TYPE_METHOD( \
+ field->number(), \
+ field->is_repeated() ? \
+ message_reflection->GetRepeated##CPPTYPE_METHOD(field, j) : \
+ message_reflection->Get##CPPTYPE_METHOD(field), \
+ output)) { \
+ return false; \
+ } \
+ 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_TYPE( FIXED32, Fixed32, UInt32)
+ HANDLE_TYPE( FIXED64, Fixed64, UInt64)
+ HANDLE_TYPE(SFIXED32, SFixed32, Int32)
+ HANDLE_TYPE(SFIXED64, SFixed64, Int64)
+
+ HANDLE_TYPE(FLOAT , Float , Float )
+ HANDLE_TYPE(DOUBLE, Double, Double)
+
+ HANDLE_TYPE(BOOL, Bool, Bool)
+
+ HANDLE_TYPE(GROUP , Group , Message)
+ HANDLE_TYPE(MESSAGE, Message, Message)
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::TYPE_ENUM: {
+ const EnumValueDescriptor* value = field->is_repeated() ?
+ message_reflection->GetRepeatedEnum(field, j) :
+ message_reflection->GetEnum(field);
+ if (!WriteEnum(field->number(), value->number(), output)) return false;
+ break;
+ }
+
+ // Handle strings separately so that we can get string references
+ // instead of copying.
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES: {
+ string scratch;
+ const string& value = field->is_repeated() ?
+ message_reflection->GetRepeatedStringReference(field, j, &scratch) :
+ message_reflection->GetStringReference(field, &scratch);
+ if (!WriteString(field->number(), value, output)) return false;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool WireFormat::SerializeMessageSetItemWithCachedSizes(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection,
+ io::CodedOutputStream* output) {
+ // Start group.
+ if (!output->WriteVarint32(kMessageSetItemStartTag)) return false;
+
+ // Write type ID.
+ if (!output->WriteVarint32(kMessageSetTypeIdTag)) return false;
+ if (!output->WriteVarint32(field->number())) return false;
+
+ // Write message.
+ if (!output->WriteVarint32(kMessageSetMessageTag)) return false;
+
+ const Message& sub_message = message_reflection->GetMessage(field);
+ if (!output->WriteVarint32(sub_message.GetCachedSize())) return false;
+ if (!sub_message.SerializeWithCachedSizes(output)) return false;
+
+ // End group.
+ if (!output->WriteVarint32(kMessageSetItemEndTag)) return false;
+
+ return true;
+}
+
+// ===================================================================
+
+int WireFormat::ByteSize(
+ const Descriptor* descriptor,
+ const Message::Reflection* message_reflection) {
+ int our_size = 0;
+
+ vector<const FieldDescriptor*> fields;
+ message_reflection->ListFields(&fields);
+ for (int i = 0; i < fields.size(); i++) {
+ our_size += FieldByteSize(fields[i], message_reflection);
+ }
+
+ if (descriptor->options().message_set_wire_format()) {
+ our_size += ComputeUnknownMessageSetItemsSize(
+ message_reflection->GetUnknownFields());
+ } else {
+ our_size += ComputeUnknownFieldsSize(
+ message_reflection->GetUnknownFields());
+ }
+
+ return our_size;
+}
+
+int WireFormat::FieldByteSize(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection) {
+ 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_reflection);
+ }
+
+ int our_size = 0;
+
+ int count = 0;
+
+ if (field->is_repeated()) {
+ count = message_reflection->FieldSize(field);
+ } else if (message_reflection->HasField(field)) {
+ count = 1;
+ }
+
+ our_size += count * TagSize(field->number(), field->type());
+
+ switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: \
+ if (field->is_repeated()) { \
+ for (int j = 0; j < count; j++) { \
+ our_size += TYPE_METHOD##Size( \
+ message_reflection->GetRepeated##CPPTYPE_METHOD(field, j)); \
+ } \
+ } else { \
+ our_size += TYPE_METHOD##Size( \
+ message_reflection->Get##CPPTYPE_METHOD(field)); \
+ } \
+ break;
+
+#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: \
+ our_size += count * 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 (int j = 0; j < count; j++) {
+ our_size += EnumSize(
+ message_reflection->GetRepeatedEnum(field, j)->number());
+ }
+ } else {
+ our_size += EnumSize(
+ message_reflection->GetEnum(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 (int j = 0; j < count; j++) {
+ string scratch;
+ const string& value = field->is_repeated() ?
+ message_reflection->GetRepeatedStringReference(field, j, &scratch) :
+ message_reflection->GetStringReference(field, &scratch);
+ our_size += StringSize(value);
+ }
+ break;
+ }
+ }
+
+ return our_size;
+}
+
+int WireFormat::MessageSetItemByteSize(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection) {
+ int our_size = kMessageSetItemTagsSize;
+
+ // type_id
+ our_size += io::CodedOutputStream::VarintSize32(field->number());
+
+ // message
+ const Message& sub_message = message_reflection->GetMessage(field);
+ int message_size = sub_message.ByteSize();
+
+ our_size += io::CodedOutputStream::VarintSize32(message_size);
+ our_size += message_size;
+
+ return our_size;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
new file mode 100644
index 00000000..d59f3fc1
--- /dev/null
+++ b/src/google/protobuf/wire_format.h
@@ -0,0 +1,446 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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 <string>
+#include <google/protobuf/message.h> // Message::Reflection
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+
+namespace protobuf {
+ namespace io {
+ class CodedInputStream; // coded_stream.h
+ class CodedOutputStream; // coded_stream.h
+ }
+ class UnknownFieldSet; // unknown_field_set.h
+}
+
+namespace protobuf {
+namespace internal {
+
+// This class is for internal use by the protocol buffer library and by
+// protocol-complier-generated message classes. It must not be called
+// directly by clients.
+//
+// This class contains helpers for implementing the binary protocol buffer
+// wire format. These helpers are called primarily by generated code. The
+// class also contains reflection-based implementations of the wire format.
+//
+// This class is really a namespace that contains only static methods.
+class LIBPROTOBUF_EXPORT WireFormat {
+ public:
+ // 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 Message::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(const Descriptor* descriptor,
+ io::CodedInputStream* input,
+ Message::Reflection* message_reflection);
+
+ // 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 bool SerializeWithCachedSizes(
+ const Descriptor* descriptor,
+ const Message::Reflection* message_reflection,
+ int size, io::CodedOutputStream* output);
+
+ // 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 int ByteSize(const Descriptor* descriptor,
+ const Message::Reflection* message_reflection);
+
+ // -----------------------------------------------------------------
+ // 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-NULL,
+ // the contents of the field will be added to it.
+ static bool SkipField(io::CodedInputStream* input, uint32 tag,
+ UnknownFieldSet* unknown_fields);
+
+ // Reads and ignores a message from the input. If unknown_fields is non-NULL,
+ // the contents will be added to it.
+ static bool SkipMessage(io::CodedInputStream* input,
+ UnknownFieldSet* unknown_fields);
+
+ // Write the contents of an UnknownFieldSet to the output.
+ static bool SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
+ io::CodedOutputStream* output);
+
+ // Same thing except for messages that have the message_set_wire_format
+ // option.
+ static bool SerializeUnknownMessageSetItems(
+ const UnknownFieldSet& unknown_fields,
+ io::CodedOutputStream* output);
+
+ // Compute the size of the UnknownFieldSet on the wire.
+ static int ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields);
+
+ // Same thing except for messages that have the message_set_wire_format
+ // option.
+ static int ComputeUnknownMessageSetItemsSize(
+ const UnknownFieldSet& unknown_fields);
+
+ // -----------------------------------------------------------------
+ // 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,
+ };
+
+ static inline WireType WireTypeForFieldType(FieldDescriptor::Type type) {
+ return kWireTypeForFieldType[type];
+ }
+
+ // Number of bits in a tag which identify the wire type.
+ static const int kTagTypeBits = 3;
+ // Mask for those bits.
+ static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1;
+
+ // Helper functions for encoding and decoding tags. (Inlined below.)
+ static uint32 MakeTag(const FieldDescriptor* field);
+ static uint32 MakeTag(int field_number, WireType type);
+ static WireType GetTagWireType(uint32 tag);
+ static int GetTagFieldNumber(uint32 tag);
+
+ // 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 EncodeFloat(float value);
+ static float DecodeFloat(uint32 value);
+ static uint64 EncodeDouble(double value);
+ static double DecodeDouble(uint64 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 ZigZagEncode32(int32 n);
+ static int32 ZigZagDecode32(uint32 n);
+ static uint64 ZigZagEncode64(int64 n);
+ static int64 ZigZagDecode64(uint64 n);
+
+ // Parse a single field. The input should start out positioned immidately
+ // after the tag.
+ static bool ParseAndMergeField(
+ uint32 tag,
+ const FieldDescriptor* field, // May be NULL for unknown
+ Message::Reflection* message_reflection,
+ io::CodedInputStream* input);
+
+ // Serialize a single field.
+ static bool SerializeFieldWithCachedSizes(
+ const FieldDescriptor* field, // Cannot be NULL
+ const Message::Reflection* message_reflection,
+ io::CodedOutputStream* output);
+
+ // 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 int FieldByteSize(
+ const FieldDescriptor* field, // Cannot be NULL
+ const Message::Reflection* message_reflection);
+
+ // =================================================================
+ // Methods for reading/writing individual field. The implementations
+ // of these methods are defined in wire_format_inl.h; you must #include
+ // that file to use these.
+
+// Avoid ugly line wrapping
+#define input io::CodedInputStream* input
+#define output io::CodedOutputStream* output
+#define field_number int field_number
+#define INL GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+
+ // Read fields, not including tags. The assumption is that you already
+ // read the tag to determine what field to read.
+ static inline bool ReadInt32 (input, int32* value);
+ static inline bool ReadInt64 (input, int64* value);
+ static inline bool ReadUInt32 (input, uint32* value);
+ static inline bool ReadUInt64 (input, uint64* value);
+ static inline bool ReadSInt32 (input, int32* value);
+ static inline bool ReadSInt64 (input, int64* value);
+ static inline bool ReadFixed32 (input, uint32* value);
+ static inline bool ReadFixed64 (input, uint64* value);
+ static inline bool ReadSFixed32(input, int32* value);
+ static inline bool ReadSFixed64(input, int64* value);
+ static inline bool ReadFloat (input, float* value);
+ static inline bool ReadDouble (input, double* value);
+ static inline bool ReadBool (input, bool* value);
+ static inline bool ReadEnum (input, int* value);
+
+ static inline bool ReadString(input, string* value);
+ static inline bool ReadBytes (input, string* value);
+
+ static inline bool ReadGroup (field_number, input, Message* value);
+ static inline bool ReadMessage(input, Message* value);
+
+ // Like above, but de-virtualize the call to MergePartialFromCodedStream().
+ // The pointer must point at an instance of MessageType, *not* a subclass (or
+ // the subclass must not override MergePartialFromCodedStream()).
+ template<typename MessageType>
+ static inline bool ReadGroupNoVirtual(field_number, input,
+ MessageType* value);
+ template<typename MessageType>
+ static inline bool ReadMessageNoVirtual(input, MessageType* value);
+
+ // Write a tag. The Write*() functions automatically include the tag, so
+ // normally there's no need to call this.
+ static inline bool WriteTag(field_number, WireType type, output) INL;
+
+ // Write fields, including tags.
+ static inline bool WriteInt32 (field_number, int32 value, output) INL;
+ static inline bool WriteInt64 (field_number, int64 value, output) INL;
+ static inline bool WriteUInt32 (field_number, uint32 value, output) INL;
+ static inline bool WriteUInt64 (field_number, uint64 value, output) INL;
+ static inline bool WriteSInt32 (field_number, int32 value, output) INL;
+ static inline bool WriteSInt64 (field_number, int64 value, output) INL;
+ static inline bool WriteFixed32 (field_number, uint32 value, output) INL;
+ static inline bool WriteFixed64 (field_number, uint64 value, output) INL;
+ static inline bool WriteSFixed32(field_number, int32 value, output) INL;
+ static inline bool WriteSFixed64(field_number, int64 value, output) INL;
+ static inline bool WriteFloat (field_number, float value, output) INL;
+ static inline bool WriteDouble (field_number, double value, output) INL;
+ static inline bool WriteBool (field_number, bool value, output) INL;
+ static inline bool WriteEnum (field_number, int value, output) INL;
+
+ static inline bool WriteString(field_number, const string& value, output) INL;
+ static inline bool WriteBytes (field_number, const string& value, output) INL;
+
+ static inline bool WriteGroup(field_number, const Message& value, output) INL;
+ static inline bool WriteMessage(
+ field_number, const Message& value, output) INL;
+
+ // 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 bool WriteGroupNoVirtual(
+ field_number, const MessageType& value, output) INL;
+ template<typename MessageType>
+ static inline bool WriteMessageNoVirtual(
+ field_number, const MessageType& value, output) INL;
+
+ // Compute the byte size of a tag. For groups, this includes both the start
+ // and end tags.
+ static inline int TagSize(field_number, FieldDescriptor::Type type);
+
+ // 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 int Int32Size ( int32 value);
+ static inline int Int64Size ( int64 value);
+ static inline int UInt32Size (uint32 value);
+ static inline int UInt64Size (uint64 value);
+ static inline int SInt32Size ( int32 value);
+ static inline int SInt64Size ( int64 value);
+ static inline int EnumSize ( int value);
+
+ // These types always have the same size.
+ static const int kFixed32Size = 4;
+ static const int kFixed64Size = 8;
+ static const int kSFixed32Size = 4;
+ static const int kSFixed64Size = 8;
+ static const int kFloatSize = 4;
+ static const int kDoubleSize = 8;
+ static const int kBoolSize = 1;
+
+ static inline int StringSize(const string& value);
+ static inline int BytesSize (const string& value);
+
+ static inline int GroupSize (const Message& value);
+ static inline int MessageSize(const Message& 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 int GroupSizeNoVirtual (const MessageType& value);
+ template<typename MessageType>
+ static inline int MessageSizeNoVirtual(const MessageType& value);
+
+#undef input
+#undef output
+#undef field_number
+#undef INL
+
+ private:
+ static const WireType kWireTypeForFieldType[];
+
+ // Parse/serialize a MessageSet::Item group. Used with messages that use
+ // opion message_set_wire_format = true.
+ static bool ParseAndMergeMessageSetItem(
+ io::CodedInputStream* input,
+ Message::Reflection* message_reflection);
+ static bool SerializeMessageSetItemWithCachedSizes(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection,
+ io::CodedOutputStream* output);
+ static int MessageSetItemByteSize(
+ const FieldDescriptor* field,
+ const Message::Reflection* message_reflection);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
+};
+
+// inline methods ====================================================
+
+// This macro does the same thing as WireFormat::MakeTag(), but the
+// result is usable as a compile-time constant, which makes it usable
+// as a switch case or a template input. WireFormat::MakeTag() is more
+// type-safe, though, so prefer it if possible.
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \
+ static_cast<uint32>( \
+ ((FIELD_NUMBER) << ::google::protobuf::internal::WireFormat::kTagTypeBits) | (TYPE))
+
+inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) {
+ return MakeTag(field->number(), WireTypeForFieldType(field->type()));
+}
+
+inline uint32 WireFormat::MakeTag(int field_number, WireType type) {
+ return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
+}
+
+inline WireFormat::WireType WireFormat::GetTagWireType(uint32 tag) {
+ return static_cast<WireType>(tag & kTagTypeMask);
+}
+
+inline int WireFormat::GetTagFieldNumber(uint32 tag) {
+ return static_cast<int>(tag >> kTagTypeBits);
+}
+
+inline uint32 WireFormat::EncodeFloat(float value) {
+ union {float f; uint32 i;};
+ f = value;
+ return i;
+}
+
+inline float WireFormat::DecodeFloat(uint32 value) {
+ union {float f; uint32 i;};
+ i = value;
+ return f;
+}
+
+inline uint64 WireFormat::EncodeDouble(double value) {
+ union {double f; uint64 i;};
+ f = value;
+ return i;
+}
+
+inline double WireFormat::DecodeDouble(uint64 value) {
+ union {double f; uint64 i;};
+ i = value;
+ return f;
+}
+
+// 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 -> uint32
+// -------------------------
+// 0 -> 0
+// -1 -> 1
+// 1 -> 2
+// -2 -> 3
+// ... -> ...
+// 2147483647 -> 4294967294
+// -2147483648 -> 4294967295
+//
+// >> encode >>
+// << decode <<
+
+inline uint32 WireFormat::ZigZagEncode32(int32 n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 31);
+}
+
+inline int32 WireFormat::ZigZagDecode32(uint32 n) {
+ return (n >> 1) ^ -static_cast<int32>(n & 1);
+}
+
+inline uint64 WireFormat::ZigZagEncode64(int64 n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 63);
+}
+
+inline int64 WireFormat::ZigZagDecode64(uint64 n) {
+ return (n >> 1) ^ -static_cast<int64>(n & 1);
+}
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_H__
diff --git a/src/google/protobuf/wire_format_inl.h b/src/google/protobuf/wire_format_inl.h
new file mode 100644
index 00000000..d8cdd8d6
--- /dev/null
+++ b/src/google/protobuf/wire_format_inl.h
@@ -0,0 +1,371 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_INL_H__
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_INL_H__
+
+#include <string>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/coded_stream.h>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline bool WireFormat::ReadInt32(io::CodedInputStream* input, int32* value) {
+ uint32 temp;
+ if (!input->ReadVarint32(&temp)) return false;
+ *value = static_cast<int32>(temp);
+ return true;
+}
+inline bool WireFormat::ReadInt64(io::CodedInputStream* input, int64* value) {
+ uint64 temp;
+ if (!input->ReadVarint64(&temp)) return false;
+ *value = static_cast<int64>(temp);
+ return true;
+}
+inline bool WireFormat::ReadUInt32(io::CodedInputStream* input, uint32* value) {
+ return input->ReadVarint32(value);
+}
+inline bool WireFormat::ReadUInt64(io::CodedInputStream* input, uint64* value) {
+ return input->ReadVarint64(value);
+}
+inline bool WireFormat::ReadSInt32(io::CodedInputStream* input, int32* value) {
+ uint32 temp;
+ if (!input->ReadVarint32(&temp)) return false;
+ *value = ZigZagDecode32(temp);
+ return true;
+}
+inline bool WireFormat::ReadSInt64(io::CodedInputStream* input, int64* value) {
+ uint64 temp;
+ if (!input->ReadVarint64(&temp)) return false;
+ *value = ZigZagDecode64(temp);
+ return true;
+}
+inline bool WireFormat::ReadFixed32(io::CodedInputStream* input,
+ uint32* value) {
+ return input->ReadLittleEndian32(value);
+}
+inline bool WireFormat::ReadFixed64(io::CodedInputStream* input,
+ uint64* value) {
+ return input->ReadLittleEndian64(value);
+}
+inline bool WireFormat::ReadSFixed32(io::CodedInputStream* input,
+ int32* value) {
+ uint32 temp;
+ if (!input->ReadLittleEndian32(&temp)) return false;
+ *value = static_cast<int32>(temp);
+ return true;
+}
+inline bool WireFormat::ReadSFixed64(io::CodedInputStream* input,
+ int64* value) {
+ uint64 temp;
+ if (!input->ReadLittleEndian64(&temp)) return false;
+ *value = static_cast<int64>(temp);
+ return true;
+}
+inline bool WireFormat::ReadFloat(io::CodedInputStream* input, float* value) {
+ uint32 temp;
+ if (!input->ReadLittleEndian32(&temp)) return false;
+ *value = DecodeFloat(temp);
+ return true;
+}
+inline bool WireFormat::ReadDouble(io::CodedInputStream* input, double* value) {
+ uint64 temp;
+ if (!input->ReadLittleEndian64(&temp)) return false;
+ *value = DecodeDouble(temp);
+ return true;
+}
+inline bool WireFormat::ReadBool(io::CodedInputStream* input, bool* value) {
+ uint32 temp;
+ if (!input->ReadVarint32(&temp)) return false;
+ *value = temp != 0;
+ return true;
+}
+inline bool WireFormat::ReadEnum(io::CodedInputStream* input, int* value) {
+ uint32 temp;
+ if (!input->ReadVarint32(&temp)) return false;
+ *value = static_cast<int>(temp);
+ return true;
+}
+
+inline bool WireFormat::ReadString(io::CodedInputStream* input, string* value) {
+ // WARNING: In wire_format.cc, both strings and bytes are handled by
+ // ReadString() to avoid code duplication. If the implementations become
+ // different, you will need to update that usage.
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ return input->ReadString(value, length);
+}
+inline bool WireFormat::ReadBytes(io::CodedInputStream* input, string* value) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ return input->ReadString(value, length);
+}
+
+
+inline bool WireFormat::ReadGroup(int field_number, io::CodedInputStream* input,
+ Message* value) {
+ if (!input->IncrementRecursionDepth()) return false;
+ if (!value->MergePartialFromCodedStream(input)) return false;
+ input->DecrementRecursionDepth();
+ // 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;
+}
+inline bool WireFormat::ReadMessage(io::CodedInputStream* input, Message* value) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (!input->IncrementRecursionDepth()) return false;
+ io::CodedInputStream::Limit limit = input->PushLimit(length);
+ if (!value->MergePartialFromCodedStream(input)) return false;
+ // Make sure that parsing stopped when the limit was hit, not at an endgroup
+ // tag.
+ if (!input->ConsumedEntireMessage()) return false;
+ input->PopLimit(limit);
+ input->DecrementRecursionDepth();
+ return true;
+}
+
+template<typename MessageType>
+inline bool WireFormat::ReadGroupNoVirtual(int field_number,
+ io::CodedInputStream* input,
+ MessageType* value) {
+ if (!input->IncrementRecursionDepth()) return false;
+ if (!value->MessageType::MergePartialFromCodedStream(input)) return false;
+ input->DecrementRecursionDepth();
+ // 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 WireFormat::ReadMessageNoVirtual(io::CodedInputStream* input,
+ MessageType* value) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ if (!input->IncrementRecursionDepth()) return false;
+ io::CodedInputStream::Limit limit = input->PushLimit(length);
+ if (!value->MessageType::MergePartialFromCodedStream(input)) return false;
+ // Make sure that parsing stopped when the limit was hit, not at an endgroup
+ // tag.
+ if (!input->ConsumedEntireMessage()) return false;
+ input->PopLimit(limit);
+ input->DecrementRecursionDepth();
+ return true;
+}
+
+// ===================================================================
+
+inline bool WireFormat::WriteTag(int field_number, WireType type,
+ io::CodedOutputStream* output) {
+ return output->WriteTag(MakeTag(field_number, type));
+}
+
+inline bool WireFormat::WriteInt32(int field_number, int32 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint32SignExtended(value);
+}
+inline bool WireFormat::WriteInt64(int field_number, int64 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint64(static_cast<uint64>(value));
+}
+inline bool WireFormat::WriteUInt32(int field_number, uint32 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint32(value);
+}
+inline bool WireFormat::WriteUInt64(int field_number, uint64 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint64(value);
+}
+inline bool WireFormat::WriteSInt32(int field_number, int32 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint32(ZigZagEncode32(value));
+}
+inline bool WireFormat::WriteSInt64(int field_number, int64 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint64(ZigZagEncode64(value));
+}
+inline bool WireFormat::WriteFixed32(int field_number, uint32 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
+ output->WriteLittleEndian32(value);
+}
+inline bool WireFormat::WriteFixed64(int field_number, uint64 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
+ output->WriteLittleEndian64(value);
+}
+inline bool WireFormat::WriteSFixed32(int field_number, int32 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
+ output->WriteLittleEndian32(static_cast<uint32>(value));
+}
+inline bool WireFormat::WriteSFixed64(int field_number, int64 value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
+ output->WriteLittleEndian64(static_cast<uint64>(value));
+}
+inline bool WireFormat::WriteFloat(int field_number, float value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
+ output->WriteLittleEndian32(EncodeFloat(value));
+}
+inline bool WireFormat::WriteDouble(int field_number, double value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
+ output->WriteLittleEndian64(EncodeDouble(value));
+}
+inline bool WireFormat::WriteBool(int field_number, bool value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint32(value ? 1 : 0);
+}
+inline bool WireFormat::WriteEnum(int field_number, int value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_VARINT, output) &&
+ output->WriteVarint32SignExtended(value);
+}
+
+inline bool WireFormat::WriteString(int field_number, const string& value,
+ io::CodedOutputStream* output) {
+ // 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.
+ return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) &&
+ output->WriteVarint32(value.size()) &&
+ output->WriteString(value);
+}
+inline bool WireFormat::WriteBytes(int field_number, const string& value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) &&
+ output->WriteVarint32(value.size()) &&
+ output->WriteString(value);
+}
+
+
+inline bool WireFormat::WriteGroup(int field_number, const Message& value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_START_GROUP, output) &&
+ value.SerializeWithCachedSizes(output) &&
+ WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+inline bool WireFormat::WriteMessage(int field_number, const Message& value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) &&
+ output->WriteVarint32(value.GetCachedSize()) &&
+ value.SerializeWithCachedSizes(output);
+}
+
+template<typename MessageType>
+inline bool WireFormat::WriteGroupNoVirtual(
+ int field_number, const MessageType& value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_START_GROUP, output) &&
+ value.MessageType::SerializeWithCachedSizes(output) &&
+ WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+template<typename MessageType>
+inline bool WireFormat::WriteMessageNoVirtual(
+ int field_number, const MessageType& value,
+ io::CodedOutputStream* output) {
+ return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) &&
+ output->WriteVarint32(value.MessageType::GetCachedSize()) &&
+ value.MessageType::SerializeWithCachedSizes(output);
+}
+
+// ===================================================================
+
+inline int WireFormat::TagSize(int field_number, FieldDescriptor::Type type) {
+ int result = io::CodedOutputStream::VarintSize32(
+ field_number << kTagTypeBits);
+ if (type == FieldDescriptor::TYPE_GROUP) {
+ // Groups have both a start and an end tag.
+ return result * 2;
+ } else {
+ return result;
+ }
+}
+
+inline int WireFormat::Int32Size(int32 value) {
+ return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+inline int WireFormat::Int64Size(int64 value) {
+ return io::CodedOutputStream::VarintSize64(static_cast<uint64>(value));
+}
+inline int WireFormat::UInt32Size(uint32 value) {
+ return io::CodedOutputStream::VarintSize32(value);
+}
+inline int WireFormat::UInt64Size(uint64 value) {
+ return io::CodedOutputStream::VarintSize64(value);
+}
+inline int WireFormat::SInt32Size(int32 value) {
+ return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
+}
+inline int WireFormat::SInt64Size(int64 value) {
+ return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value));
+}
+inline int WireFormat::EnumSize(int value) {
+ return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+
+inline int WireFormat::StringSize(const string& value) {
+ return io::CodedOutputStream::VarintSize32(value.size()) +
+ value.size();
+}
+inline int WireFormat::BytesSize(const string& value) {
+ return io::CodedOutputStream::VarintSize32(value.size()) +
+ value.size();
+}
+
+
+inline int WireFormat::GroupSize(const Message& value) {
+ return value.ByteSize();
+}
+inline int WireFormat::MessageSize(const Message& value) {
+ int size = value.ByteSize();
+ return io::CodedOutputStream::VarintSize32(size) + size;
+}
+
+template<typename MessageType>
+inline int WireFormat::GroupSizeNoVirtual(const MessageType& value) {
+ return value.MessageType::ByteSize();
+}
+template<typename MessageType>
+inline int WireFormat::MessageSizeNoVirtual(const MessageType& value) {
+ int size = value.MessageType::ByteSize();
+ return io::CodedOutputStream::VarintSize32(size) + size;
+}
+
+} // namespace internal
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_INL_H__
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
new file mode 100644
index 00000000..7430786c
--- /dev/null
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -0,0 +1,526 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+// 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/wire_format_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.pb.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(WireFormatTest, MaxFieldNumber) {
+ // Make sure the max field number constant is accurate.
+ EXPECT_EQ((1 << (32 - WireFormat::kTagTypeBits)) - 1,
+ FieldDescriptor::kMaxNumber);
+}
+
+TEST(WireFormatTest, Parse) {
+ unittest::TestAllTypes source, dest;
+ 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(unittest::TestAllTypes::descriptor(),
+ &input, dest.GetReflection());
+
+ // Check.
+ TestUtil::ExpectAllFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParseExtensions) {
+ unittest::TestAllExtensions source, dest;
+ 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(unittest::TestAllExtensions::descriptor(),
+ &input, dest.GetReflection());
+
+ // Check.
+ TestUtil::ExpectAllExtensionsSet(dest);
+}
+
+TEST(WireFormatTest, ByteSize) {
+ unittest::TestAllTypes message;
+ TestUtil::SetAllFields(&message);
+
+ EXPECT_EQ(message.ByteSize(),
+ WireFormat::ByteSize(unittest::TestAllTypes::descriptor(),
+ message.GetReflection()));
+ message.Clear();
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(unittest::TestAllTypes::descriptor(),
+ message.GetReflection()));
+}
+
+TEST(WireFormatTest, ByteSizeExtensions) {
+ unittest::TestAllExtensions message;
+ TestUtil::SetAllExtensions(&message);
+
+ EXPECT_EQ(message.ByteSize(),
+ WireFormat::ByteSize(unittest::TestAllExtensions::descriptor(),
+ message.GetReflection()));
+ message.Clear();
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(unittest::TestAllExtensions::descriptor(),
+ message.GetReflection()));
+}
+
+TEST(WireFormatTest, Serialize) {
+ unittest::TestAllTypes message;
+ string generated_data;
+ string dynamic_data;
+
+ TestUtil::SetAllFields(&message);
+ int size = message.ByteSize();
+
+ // Serialize using the generated code.
+ {
+ io::StringOutputStream raw_output(&generated_data);
+ io::CodedOutputStream output(&raw_output);
+ message.SerializeWithCachedSizes(&output);
+ }
+
+ // Serialize using WireFormat.
+ {
+ io::StringOutputStream raw_output(&dynamic_data);
+ io::CodedOutputStream output(&raw_output);
+ WireFormat::SerializeWithCachedSizes(
+ unittest::TestAllTypes::descriptor(),
+ message.GetReflection(), size, &output);
+ }
+
+ // Should be the same.
+ // Don't use EXPECT_EQ here because we're comparing raw binary data and
+ // we really don't want it dumped to stdout on failure.
+ EXPECT_TRUE(dynamic_data == generated_data);
+}
+
+TEST(WireFormatTest, SerializeExtensions) {
+ unittest::TestAllExtensions message;
+ string generated_data;
+ string dynamic_data;
+
+ TestUtil::SetAllExtensions(&message);
+ int size = message.ByteSize();
+
+ // Serialize using the generated code.
+ {
+ io::StringOutputStream raw_output(&generated_data);
+ io::CodedOutputStream output(&raw_output);
+ message.SerializeWithCachedSizes(&output);
+ }
+
+ // Serialize using WireFormat.
+ {
+ io::StringOutputStream raw_output(&dynamic_data);
+ io::CodedOutputStream output(&raw_output);
+ WireFormat::SerializeWithCachedSizes(
+ unittest::TestAllExtensions::descriptor(),
+ message.GetReflection(), size, &output);
+ }
+
+ // Should be the same.
+ // Don't use EXPECT_EQ here because we're comparing raw binary data and
+ // we really don't want it dumped to stdout on failure.
+ EXPECT_TRUE(dynamic_data == generated_data);
+}
+
+TEST(WireFormatTest, SerializeFieldsAndExtensions) {
+ unittest::TestFieldOrderings message;
+ string generated_data;
+ string dynamic_data;
+
+ TestUtil::SetAllFieldsAndExtensions(&message);
+ int size = message.ByteSize();
+
+ // Serialize using the generated code.
+ {
+ io::StringOutputStream raw_output(&generated_data);
+ io::CodedOutputStream output(&raw_output);
+ message.SerializeWithCachedSizes(&output);
+ }
+
+ // Serialize using WireFormat.
+ {
+ io::StringOutputStream raw_output(&dynamic_data);
+ io::CodedOutputStream output(&raw_output);
+ WireFormat::SerializeWithCachedSizes(
+ unittest::TestFieldOrderings::descriptor(),
+ message.GetReflection(), size, &output);
+ }
+
+ // Should be the same.
+ // Don't use EXPECT_EQ here because we're comparing raw binary data and
+ // we really don't want it dumped to stdout on failure.
+ EXPECT_TRUE(dynamic_data == generated_data);
+
+ // Should output in canonical order.
+ TestUtil::ExpectAllFieldsAndExtensionsInOrder(dynamic_data);
+ TestUtil::ExpectAllFieldsAndExtensionsInOrder(generated_data);
+}
+
+const int kUnknownTypeId = 1550055;
+
+TEST(WireFormatTest, SerializeMessageSet) {
+ // Set up a TestMessageSet with two known messages and an unknown one.
+ 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()->AddField(kUnknownTypeId)
+ ->add_length_delimited("bar");
+
+ 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, 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");
+ }
+
+ string data;
+ ASSERT_TRUE(raw.SerializeToString(&data));
+
+ // Parse as a TestMessageSet and check the contents.
+ 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(1, message_set.unknown_fields().field(0).length_delimited_size());
+ EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited(0));
+}
+
+TEST(WireFormatTest, RecursionLimit) {
+ unittest::TestRecursiveMessage message;
+ message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
+ 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, UnknownFieldRecursionLimit) {
+ unittest::TestEmptyMessage message;
+ message.mutable_unknown_fields()
+ ->AddField(1234)->add_group()
+ ->AddField(1234)->add_group()
+ ->AddField(1234)->add_group()
+ ->AddField(1234)->add_group()
+ ->AddField(1234)->add_varint(123);
+ 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) GOOGLE_LONGLONG(x)
+#define ULL(x) GOOGLE_ULONGLONG(x)
+#define ZigZagEncode32(x) WireFormat::ZigZagEncode32(x)
+#define ZigZagDecode32(x) WireFormat::ZigZagDecode32(x)
+#define ZigZagEncode64(x) WireFormat::ZigZagEncode64(x)
+#define ZigZagDecode64(x) WireFormat::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))));
+}
+
+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.
+ string MakeInvalidEmbeddedMessage(const char* bytes, int size) {
+ const FieldDescriptor* field =
+ unittest::TestAllTypes::descriptor()->FindFieldByName(
+ "optional_nested_message");
+ GOOGLE_CHECK(field != NULL);
+
+ string result;
+
+ {
+ io::StringOutputStream raw_output(&result);
+ io::CodedOutputStream output(&raw_output);
+
+ EXPECT_TRUE(WireFormat::WriteString(
+ field->number(), 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.
+ string MakeInvalidGroup(const char* bytes, int size, bool include_end_tag) {
+ const FieldDescriptor* field =
+ unittest::TestAllTypes::descriptor()->FindFieldByName(
+ "optionalgroup");
+ GOOGLE_CHECK(field != NULL);
+
+ string result;
+
+ {
+ io::StringOutputStream raw_output(&result);
+ io::CodedOutputStream output(&raw_output);
+
+ EXPECT_TRUE(output.WriteVarint32(WireFormat::MakeTag(field)));
+ EXPECT_TRUE(output.WriteString(string(bytes, size)));
+ if (include_end_tag) {
+ EXPECT_TRUE(
+ output.WriteVarint32(WireFormat::MakeTag(
+ field->number(), WireFormat::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, 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 ForeignMessage so that the group made by MakeInvalidGroup will not
+ // be a known tag number.
+ unittest::ForeignMessage 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)));
+}
+
+} // namespace
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/gtest/CHANGES b/src/gtest/CHANGES
new file mode 100644
index 00000000..871ef1fb
--- /dev/null
+++ b/src/gtest/CHANGES
@@ -0,0 +1,3 @@
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Test
diff --git a/src/gtest/CONTRIBUTORS b/src/gtest/CONTRIBUTORS
new file mode 100644
index 00000000..31341833
--- /dev/null
+++ b/src/gtest/CONTRIBUTORS
@@ -0,0 +1,23 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Ajay Joshi <jaj@google.com>
+Bharat Mediratta <bharat@menalto.com>
+Chandler Carruth <chandlerc@google.com>
+Chris Prince <cprince@google.com>
+Chris Taylor <taylorc@google.com>
+Jeffrey Yasskin <jyasskin@google.com>
+Keir Mierle <mierle@gmail.com>
+Keith Ray <keith.ray@gmail.com>
+Markus Heule <markus.heule@gmail.com>
+Patrick Hanna <phanna@google.com>
+Patrick Riley <pfr@google.com>
+Peter Kaminski <piotrk@google.com>
+Russ Cox <rsc@google.com>
+Russ Rufer <russ@pentad.com>
+Sean Mcafee <eefacm@gmail.com>
+Sigurður Ásgeirsson <siggi@google.com>
+Tracy Bialik <tracy@pentad.com>
+Zhanyong Wan <wan@google.com>
diff --git a/src/gtest/COPYING b/src/gtest/COPYING
new file mode 100644
index 00000000..1941a11f
--- /dev/null
+++ b/src/gtest/COPYING
@@ -0,0 +1,28 @@
+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.
diff --git a/src/gtest/README b/src/gtest/README
new file mode 100644
index 00000000..0e170475
--- /dev/null
+++ b/src/gtest/README
@@ -0,0 +1,150 @@
+This directory contains Google Test, described below. It is used by the
+Protocol Buffer C++ unit tests. If you would like to use Google Test
+yourself, you should probably download it from the URL mentioned below,
+not attempt to use the sources in this package.
+
+Two changes were made from the original sources:
+* gtest.cc's #include of gtest-internal-inl.h was modified to reflect the
+ environment it is being built in (replaced "src/" with "gtest/").
+* GetThreadCount() in gtest-port.h was hard-coded to return 1 rather than 0,
+ since the Protocol Buffer tests do not use threads.
+
+The original Google Test README follows.
+
+======================================================================
+
+Google C++ Testing Framework
+============================
+http://code.google.com/p/googletest/
+
+Overview
+--------
+Google's framework for writing C++ tests on a variety of platforms (Linux, Mac
+OS X, Windows, Windows CE, and Symbian). Based on the xUnit architecture.
+Supports automatic test discovery, a rich set of assertions, user-defined
+assertions, death tests, fatal and non-fatal failures, various options for
+running the tests, and XML test report generation.
+
+Please see the project page above for more information as well as mailing lists
+for questions, discussions, and development. There is also an IRC channel on
+OFTC (irc.oftc.net) #gtest available. Please join us!
+
+Requirements
+------------
+Google Test is designed to have fairly minimal requirements to build and use
+with your projects, but there are some. Currently, the only Operating System
+(OS) on which Google Test is known to build properly is Linux, but we are
+actively working on Windows and Mac support as well. The source code itself is
+already portable across many other platforms, but we are still developing
+robust build systems for each.
+
+### Linux Requirements ###
+These are the base requirements to build and use Google Test from a source
+package (as described below):
+ * GNU-compatible Make or "gmake"
+ * POSIX-standard shell
+ * POSIX(-2) Regular Expressions (regex.h)
+ * A C++98 standards compliant compiler
+
+Furthermore, if you are building Google Test from a VCS Checkout (also
+described below), there are further requirements:
+ * Automake version 1.9 or newer
+ * Autoconf version 2.59 or newer
+ * Libtool / Libtoolize
+ * Python version 2.4 or newer
+
+Getting the Source
+------------------
+There are two primary ways of getting Google Test's source code: you can
+download a source release in your preferred archive format, or directly check
+out the source from a Version Control System (VCS, we use Google Code's
+Subversion hosting). The VCS checkout requires a few extra steps and some extra
+software packages on your system, but lets you track development, and make
+patches to contribute much more easily, so we highly encourage it.
+
+### VCS Checkout: ###
+The first step is to select whether you want to check out the main line of
+development on Google Test, or one of the released branches. The former will be
+much more active and have the latest features, but the latter provides much
+more stability and predictability. Choose whichever fits your needs best, and
+proceed with the following Subversion commands:
+
+ $ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
+
+or for a release version X.Y.*'s branch:
+
+ $ svn checkout http://googletest.googlecode.com/svn/branches/release-X.Y/ gtest-X.Y-svn
+
+Next you will need to prepare the GNU Autotools build system. Enter the
+target directory of the checkout command you used ('gtest-svn' or
+'gtest-X.Y-svn' above) and proceed with the following commands:
+
+ $ aclocal-1.9 # Where "1.9" must match the following automake command
+ $ libtoolize -c
+ $ autoheader
+ $ automake-1.9 -ac # See Automake version requirements above
+ $ autoconf
+
+While this is a bit complicated, it will most often be automatically re-run by
+your "make" invocations, so in practice you shouldn't need to worry too much.
+Once you have completed these steps, your VCS checkout should be equivalent to
+a source package, and you may continue with those directions, skipping over the
+acquiring and unpacking of the source itself, as the VCS has done that for you.
+
+### Source Package: ###
+Google Test is also released in source packages which can be downloaded from
+its Google Code download page[1]. Several different archive formats are
+provided, but the only difference is the tools used to manipulate them, and the
+size of the resulting file. Download whichever you are most comfortable with.
+
+ [1] Google Test Downloads: http://code.google.com/p/googletest/downloads/list
+
+Once downloaded expand the archive using whichever tools you prefer for that
+type. This will always result in a new directory with the name "gtest-X.Y.Z"
+which contains all of the source code. Here are some examples in Linux:
+
+ $ tar -xvzf gtest-X.Y.Z.tar.gz
+ $ tar -xvjf gtest-X.Y.Z.tar.bz2
+ $ unzip gtest-X.Y.Z.zip
+
+Building the Source
+-------------------
+There are two primary options for building the source at this point: build it
+inside the source code tree, or in a separate directory. We recommend building
+in a separate directory as that tends to produce both more consistent results
+and be easier to clean up should anything go wrong, but both patterns are
+supported. The only hard restriction is that while the build directory can be
+a subdirectory of the source directory, the opposite is not possible and will
+result in errors. Once you have selected where you wish to build Google Test,
+create the directory if necessary, and enter it. The following steps apply for
+either approach by simply substituting the shell variable SRCDIR with "." for
+building inside the source directory, and the relative path to the source
+directory otherwise.
+
+ $ ${SRCDIR}/configure # Standard GNU configure script, --help for more info
+ $ make # Standard makefile following GNU conventions
+
+Other programs will only be able to use Google Test's functionality if you
+install it in a location which they can access, in Linux this is typically
+under '/usr/local'. The following command will install all of the Google Test
+libraries, public headers, and utilities necessary for other programs and
+libraries to leverage it:
+
+ $ sudo make install # Not necessary, but allows use by other programs
+
+TODO(chandlerc@google.com): This section needs to be expanded when the
+'gtest-config' script is finished and Autoconf macro's are provided (or not
+provided) in order to properly reflect the process for other programs to
+locate, include, and link against Google Test.
+
+Finally, should you need to remove Google Test from your system after having
+installed it, run the following command, and it will back out its changes.
+However, note carefully that you must run this command on the *same* Google
+Test build that you ran the install from, or the results are not predictable.
+If you install Google Test on your system, and are working from a VCS checkout,
+make sure you run this *before* updating your checkout of the source in order
+to uninstall the same version which you installed.
+
+ $ sudo make uninstall # Must be run against the exact same build as "install"
+
+Happy testing!
diff --git a/src/gtest/gen_gtest_pred_impl.py b/src/gtest/gen_gtest_pred_impl.py
new file mode 100755
index 00000000..7cb31da2
--- /dev/null
+++ b/src/gtest/gen_gtest_pred_impl.py
@@ -0,0 +1,733 @@
+#!/usr/bin/python2.4
+#
+# Copyright 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.
+
+"""gen_gtest_pred_impl.py v0.1
+
+Generates the implementation of Google Test predicate assertions and
+accompanying tests.
+
+Usage:
+
+ gen_gtest_pred_impl.py MAX_ARITY
+
+where MAX_ARITY is a positive integer.
+
+The command generates the implementation of up-to MAX_ARITY-ary
+predicate assertions, and writes it to file gtest_pred_impl.h in the
+directory where the script is. It also generates the accompanying
+unit test in file gtest_pred_impl_unittest.cc.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import sys
+import time
+
+# Where this script is.
+SCRIPT_DIR = os.path.dirname(sys.argv[0])
+
+# Where to store the generated header.
+HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h')
+
+# Where to store the generated unit test.
+UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc')
+
+
+def HeaderPreamble(n):
+ """Returns the preamble for the header file.
+
+ Args:
+ n: the maximum arity of the predicate macros to be generated.
+ """
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n),
+ 'n' : n
+ }
+
+ return (
+"""// Copyright 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.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most %(n)s.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT(expression, on_failure) \\
+ GTEST_AMBIGUOUS_ELSE_BLOCKER \\
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \\
+ ; \\
+ else \\
+ on_failure(gtest_ar.failure_message())
+""" % DEFS)
+
+
+def Arity(n):
+ """Returns the English name of the given arity."""
+
+ if n < 0:
+ return None
+ elif n <= 3:
+ return ['nullary', 'unary', 'binary', 'ternary'][n]
+ else:
+ return '%s-ary' % n
+
+
+def Title(word):
+ """Returns the given word in title case. The difference between
+ this and string's title() method is that Title('4-ary') is '4-ary'
+ while '4-ary'.title() is '4-Ary'."""
+
+ return word[0].upper() + word[1:]
+
+
+def OneTo(n):
+ """Returns the list [1, 2, 3, ..., n]."""
+
+ return range(1, n + 1)
+
+
+def Iter(n, format, sep=''):
+ """Given a positive integer n, a format string that contains 0 or
+ more '%s' format specs, and optionally a separator string, returns
+ the join of n strings, each formatted with the format string on an
+ iterator ranged from 1 to n.
+
+ Example:
+
+ Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'.
+ """
+
+ # How many '%s' specs are in format?
+ spec_count = len(format.split('%s')) - 1
+ return sep.join([format % (spec_count * (i,)) for i in OneTo(n)])
+
+
+def ImplementationForArity(n):
+ """Returns the implementation of n-ary predicate assertions."""
+
+ # A map the defines the values used in the implementation template.
+ DEFS = {
+ 'n' : str(n),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n))
+ }
+
+ impl = """
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+template <typename Pred""" % DEFS
+
+ impl += Iter(n, """,
+ typename T%s""")
+
+ impl += """>
+AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS
+
+ impl += Iter(n, """,
+ const char* e%s""")
+
+ impl += """,
+ Pred pred"""
+
+ impl += Iter(n, """,
+ const T%s& v%s""")
+
+ impl += """) {
+ if (pred(%(vs)s)) return AssertionSuccess();
+
+ Message msg;
+""" % DEFS
+
+ impl += ' msg << pred_text << "("'
+
+ impl += Iter(n, """
+ << e%s""", sep=' << ", "')
+
+ impl += ' << ") evaluates to false, where"'
+
+ impl += Iter(n, """
+ << "\\n" << e%s << " evaluates to " << v%s""")
+
+ impl += """;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT%(n)s(pred_format, %(vs)s, on_failure)\\
+ GTEST_ASSERT(pred_format(%(vts)s, %(vs)s),\\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+#define GTEST_PRED%(n)s(pred, %(vs)s, on_failure)\\
+ GTEST_ASSERT(::testing::AssertPred%(n)sHelper(#pred""" % DEFS
+
+ impl += Iter(n, """, \\
+ #v%s""")
+
+ impl += """, \\
+ pred"""
+
+ impl += Iter(n, """, \\
+ v%s""")
+
+ impl += """), on_failure)
+
+// %(Arity)s predicate assertion macros.
+#define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s(pred, %(vs)s, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s(pred_format, %(vs)s, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s(pred, %(vs)s, GTEST_FATAL_FAILURE)
+
+""" % DEFS
+
+ return impl
+
+
+def HeaderPostamble():
+ """Returns the postamble for the header file."""
+
+ return """
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+"""
+
+
+def GenerateFile(path, content):
+ """Given a file path and a content string, overwrites it with the
+ given content."""
+
+ print 'Updating file %s . . .' % path
+
+ f = file(path, 'w+')
+ print >>f, content,
+ f.close()
+
+ print 'File %s has been updated.' % path
+
+
+def GenerateHeader(n):
+ """Given the maximum arity n, updates the header file that implements
+ the predicate assertions."""
+
+ GenerateFile(HEADER,
+ HeaderPreamble(n)
+ + ''.join([ImplementationForArity(i) for i in OneTo(n)])
+ + HeaderPostamble())
+
+
+def UnitTestPreamble():
+ """Returns the preamble for the unit test file."""
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]),
+ }
+
+ return (
+"""// Copyright 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.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+
+// Regression test for gtest_pred_impl.h
+//
+// This file is generated by a script and quite long. If you intend to
+// learn how Google Test works by reading its unit tests, read
+// gtest_unittest.cc instead.
+//
+// This is intended as a regression test for the Google Test predicate
+// assertions. We compile it as part of the gtest_unittest target
+// only to keep the implementation tidy and compact, as it is quite
+// involved to set up the stage for testing Google Test using Google
+// Test itself.
+//
+// Currently, gtest_unittest takes ~11 seconds to run in the testing
+// daemon. In the future, if it grows too large and needs much more
+// time to finish, we should consider separating this file into a
+// stand-alone regression test.
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+// A user-defined data type.
+struct Bool {
+ explicit Bool(int val) : value(val != 0) {}
+
+ bool operator>(int n) const { return value > Bool(n).value; }
+
+ Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); }
+
+ bool operator==(const Bool& rhs) const { return value == rhs.value; }
+
+ bool value;
+};
+
+// Enables Bool to be used in assertions.
+std::ostream& operator<<(std::ostream& os, const Bool& x) {
+ return os << (x.value ? "true" : "false");
+}
+
+""" % DEFS)
+
+
+def TestsForArity(n):
+ """Returns the tests for n-ary predicate assertions."""
+
+ # A map that defines the values used in the template for the tests.
+ DEFS = {
+ 'n' : n,
+ 'es' : Iter(n, 'e%s', sep=', '),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'tvs' : Iter(n, 'T%s v%s', sep=', '),
+ 'int_vs' : Iter(n, 'int v%s', sep=', '),
+ 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '),
+ 'types' : Iter(n, 'typename T%s', sep=', '),
+ 'v_sum' : Iter(n, 'v%s', sep=' + '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n)),
+ }
+
+ tests = (
+"""// Sample functions/functors for testing %(arity)s predicate assertions.
+
+// A %(arity)s predicate function.
+template <%(types)s>
+bool PredFunction%(n)s(%(tvs)s) {
+ return %(v_sum)s > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction%(n)sInt(%(int_vs)s) {
+ return %(v_sum)s > 0;
+}
+bool PredFunction%(n)sBool(%(Bool_vs)s) {
+ return %(v_sum)s > 0;
+}
+""" % DEFS)
+
+ tests += """
+// A %(arity)s predicate functor.
+struct PredFunctor%(n)s {
+ template <%(types)s>
+ bool operator()(""" % DEFS
+
+ tests += Iter(n, 'const T%s& v%s', sep=""",
+ """)
+
+ tests += """) {
+ return %(v_sum)s > 0;
+ }
+};
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter function.
+template <%(types)s>
+testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) {
+ if (PredFunction%(n)s(%(vs)s))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << """ % DEFS
+
+ tests += Iter(n, 'e%s', sep=' << " + " << ')
+
+ tests += """
+ << " is expected to be positive, but evaluates to "
+ << %(v_sum)s << ".";
+ return testing::AssertionFailure(msg);
+}
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter functor.
+struct PredFormatFunctor%(n)s {
+ template <%(types)s>
+ testing::AssertionResult operator()(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) const {
+ return PredFormatFunction%(n)s(%(es)s, %(vs)s);
+ }
+};
+""" % DEFS
+
+ tests += """
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+
+class Predicate%(n)sTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;""" % DEFS
+
+ tests += """
+ """ + Iter(n, 'n%s_ = ') + """0;
+ }
+"""
+
+ tests += """
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once."""
+
+ tests += ''.join(["""
+ EXPECT_EQ(1, n%s_) <<
+ "The predicate assertion didn't evaluate argument %s "
+ "exactly once.";""" % (i, i + 1) for i in OneTo(n)])
+
+ tests += """
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+""" % DEFS
+
+ tests += Iter(n, """
+ static int n%s_;""")
+
+ tests += """
+};
+
+bool Predicate%(n)sTest::expected_to_finish_;
+bool Predicate%(n)sTest::finished_;
+""" % DEFS
+
+ tests += Iter(n, """int Predicate%%(n)sTest::n%s_;
+""") % DEFS
+
+ tests += """
+typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest;
+""" % DEFS
+
+ def GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type):
+ """Returns the test for a predicate assertion macro.
+
+ Args:
+ use_format: true iff the assertion is a *_PRED_FORMAT*.
+ use_assert: true iff the assertion is a ASSERT_*.
+ expect_failure: true iff the assertion is expected to fail.
+ use_functor: true iff the first argument of the assertion is
+ a functor (as opposed to a function)
+ use_user_type: true iff the predicate functor/function takes
+ argument(s) of a user-defined type.
+
+ Example:
+
+ GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior
+ of a successful EXPECT_PRED_FORMATn() that takes a functor
+ whose arguments have built-in types."""
+
+ if use_assert:
+ assrt = 'ASSERT' # 'assert' is reserved, so we cannot use
+ # that identifier here.
+ else:
+ assrt = 'EXPECT'
+
+ assertion = assrt + '_PRED'
+
+ if use_format:
+ pred_format = 'PredFormat'
+ assertion += '_FORMAT'
+ else:
+ pred_format = 'Pred'
+
+ assertion += '%(n)s' % DEFS
+
+ if use_functor:
+ pred_format_type = 'functor'
+ pred_format += 'Functor%(n)s()'
+ else:
+ pred_format_type = 'function'
+ pred_format += 'Function%(n)s'
+ if not use_format:
+ if use_user_type:
+ pred_format += 'Bool'
+ else:
+ pred_format += 'Int'
+
+ test_name = pred_format_type.title()
+
+ if use_user_type:
+ arg_type = 'user-defined type (Bool)'
+ test_name += 'OnUserType'
+ if expect_failure:
+ arg = 'Bool(n%s_++)'
+ else:
+ arg = 'Bool(++n%s_)'
+ else:
+ arg_type = 'built-in type (int)'
+ test_name += 'OnBuiltInType'
+ if expect_failure:
+ arg = 'n%s_++'
+ else:
+ arg = '++n%s_'
+
+ if expect_failure:
+ successful_or_failed = 'failed'
+ expected_or_not = 'expected.'
+ test_name += 'Failure'
+ else:
+ successful_or_failed = 'successful'
+ expected_or_not = 'UNEXPECTED!'
+ test_name += 'Success'
+
+ # A map that defines the values used in the test template.
+ defs = DEFS.copy()
+ defs.update({
+ 'assert' : assrt,
+ 'assertion' : assertion,
+ 'test_name' : test_name,
+ 'pf_type' : pred_format_type,
+ 'pf' : pred_format,
+ 'arg_type' : arg_type,
+ 'arg' : arg,
+ 'successful' : successful_or_failed,
+ 'expected' : expected_or_not,
+ })
+
+ test = """
+// Tests a %(successful)s %(assertion)s where the
+// predicate-formatter is a %(pf_type)s on a %(arg_type)s.
+TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs
+
+ indent = (len(assertion) + 3)*' '
+ extra_indent = ''
+
+ if expect_failure:
+ extra_indent = ' '
+ if use_assert:
+ test += """
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT"""
+ else:
+ test += """
+ EXPECT_NONFATAL_FAILURE({ // NOLINT"""
+
+ test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs
+
+ test = test % defs
+ test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs)
+ test += ');\n' + extra_indent + ' finished_ = true;\n'
+
+ if expect_failure:
+ test += ' }, "");\n'
+
+ test += '}\n'
+ return test
+
+ # Generates tests for all 2**6 = 64 combinations.
+ tests += ''.join([GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type)
+ for use_format in [0, 1]
+ for use_assert in [0, 1]
+ for expect_failure in [0, 1]
+ for use_functor in [0, 1]
+ for use_user_type in [0, 1]
+ ])
+
+ return tests
+
+
+def UnitTestPostamble():
+ """Returns the postamble for the tests."""
+
+ return ''
+
+
+def GenerateUnitTest(n):
+ """Returns the tests for up-to n-ary predicate assertions."""
+
+ GenerateFile(UNIT_TEST,
+ UnitTestPreamble()
+ + ''.join([TestsForArity(i) for i in OneTo(n)])
+ + UnitTestPostamble())
+
+
+def _Main():
+ """The entry point of the script. Generates the header file and its
+ unit test."""
+
+ if len(sys.argv) != 2:
+ print __doc__
+ print 'Author: ' + __author__
+ sys.exit(1)
+
+ n = int(sys.argv[1])
+ GenerateHeader(n)
+ GenerateUnitTest(n)
+
+
+if __name__ == '__main__':
+ _Main()
diff --git a/src/gtest/gtest-death-test.cc b/src/gtest/gtest-death-test.cc
new file mode 100644
index 00000000..09fdd3ff
--- /dev/null
+++ b/src/gtest/gtest-death-test.cc
@@ -0,0 +1,751 @@
+// 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: wan@google.com (Zhanyong Wan)
+//
+// This file implements death tests.
+
+#include <gtest/gtest-death-test.h>
+#include <gtest/internal/gtest-port.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION
+#include "gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+namespace internal {
+GTEST_DEFINE_string(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "colons. This flag is specified if and only if the current "
+ "process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+}
+
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static String ExitSummary(int exit_code) {
+ Message m;
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+#endif
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+ return !ExitedWithCode(0)(exit_status);
+}
+
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static String DeathTestThreadWarning(size_t thread_count) {
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME << " ";
+ if (thread_count == 0)
+ msg << "couldn't detect the number of threads.";
+ else
+ msg << "detected " << thread_count << " threads.";
+ return msg.GetString();
+}
+
+// Static string containing a description of the outcome of the
+// last death test.
+static String last_death_test_message;
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test
+// can conclude. DIED means that the process died while executing the
+// test code; LIVED means that process lived beyond the end of the test
+// code; and RETURNED means that the test statement attempted a "return,"
+// which is not allowed. IN_PROGRESS means the test has not yet
+// concluded.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const char* format, ...) {
+ // This function may be called from a threadsafe-style death test
+ // child process, which operates on a very small stack. Use the
+ // heap for any additional non-miniscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ va_list args;
+ va_start(args, format);
+
+ if (flag != NULL) {
+ FILE* parent = fdopen(flag->status_fd, "w");
+ fputc(kDeathTestInternalError, parent);
+ vfprintf(parent, format, args);
+ fclose(parent);
+ va_end(args);
+ _exit(1);
+ } else {
+ vfprintf(stderr, format, args);
+ va_end(args);
+ abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+#define GTEST_DEATH_TEST_CHECK(expression) \
+ do { \
+ if (!(expression)) { \
+ DeathTestAbort("CHECK failed: File %s, line %d: %s", \
+ __FILE__, __LINE__, #expression); \
+ } \
+ } while (0)
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+#define GTEST_DEATH_TEST_CHECK_SYSCALL(expression) \
+ do { \
+ int retval; \
+ do { \
+ retval = (expression); \
+ } while (retval == -1 && errno == EINTR); \
+ if (retval == -1) { \
+ DeathTestAbort("CHECK failed: File %s, line %d: %s != -1", \
+ __FILE__, __LINE__, #expression); \
+ } \
+ } while (0)
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == NULL) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message.c_str();
+}
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTest {
+ public:
+ ForkingDeathTest(const char* statement, const RE* regex);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual bool Passed(bool status_ok);
+ virtual void Abort(AbortReason reason);
+
+ protected:
+ void set_forked(bool forked) { forked_ = forked; }
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ private:
+ // The textual content of the code this object is testing.
+ const char* const statement_;
+ // The regular expression which test output must match.
+ const RE* const regex_;
+ // True if the death test successfully forked.
+ bool forked_;
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+ // File descriptors for communicating the death test's status byte.
+ int read_fd_; // Always -1 in the child process.
+ int write_fd_; // Always -1 in the parent process.
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)
+ : DeathTest(),
+ statement_(statement),
+ regex_(regex),
+ forked_(false),
+ child_pid_(-1),
+ read_fd_(-1),
+ write_fd_(-1),
+ status_(-1),
+ outcome_(IN_PROGRESS) {
+}
+
+// Reads an internal failure message from a file descriptor, then calls
+// LOG(FATAL) with that message. Called from a death test parent process
+// to read a failure message from the death test child process.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ ssize_t num_read;
+
+ do {
+ while ((num_read = read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ // TODO(smcafee): Maybe just FAIL the test instead?
+ if (num_read == 0) {
+ GTEST_LOG(FATAL, error);
+ } else {
+ GTEST_LOG(FATAL,
+ Message() << "Error while reading death test internal: "
+ << strerror(errno) << " [" << errno << "]");
+ }
+}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!forked_)
+ return 0;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ char flag;
+ ssize_t bytes_read;
+
+ do {
+ bytes_read = read(read_fd_, &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ outcome_ = DIED;
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ outcome_ = RETURNED;
+ break;
+ case kDeathTestLived:
+ outcome_ = LIVED;
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd_); // Does not return.
+ break;
+ default:
+ GTEST_LOG(FATAL,
+ Message() << "Death test child process reported unexpected "
+ << "status byte (" << static_cast<unsigned int>(flag)
+ << ")");
+ }
+ } else {
+ GTEST_LOG(FATAL,
+ Message() << "Read from death test child process failed: "
+ << strerror(errno));
+ }
+
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(read_fd_));
+ GTEST_DEATH_TEST_CHECK_SYSCALL(waitpid(child_pid_, &status_, 0));
+ return status_;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: an enumeration describing how the death test
+// concluded: DIED, LIVED, or RETURNED. The death test fails
+// in the latter two cases
+// status: the exit status of the child process, in the format
+// specified by wait(2)
+// regex: a regular expression object to be applied to
+// the test's captured standard error output; the death test
+// fails if it does not match
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met. Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the static variable last_death_test_message.
+bool ForkingDeathTest::Passed(bool status_ok) {
+ if (!forked_)
+ return false;
+
+#if GTEST_HAS_GLOBAL_STRING
+ const ::string error_message = GetCapturedStderr();
+#else
+ const ::std::string error_message = GetCapturedStderr();
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement_ << "\n";
+ switch (outcome_) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg: " << error_message;
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg: " << error_message;
+ break;
+ case DIED:
+ if (status_ok) {
+ if (RE::PartialMatch(error_message, *regex_)) {
+ success = true;
+ } else {
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << regex_->pattern() << "\n"
+ << "Actual msg: " << error_message;
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status_) << "\n";
+ }
+ break;
+ default:
+ GTEST_LOG(FATAL,
+ "DeathTest::Passed somehow called before conclusion of test");
+ }
+
+ last_death_test_message = buffer.GetString();
+ return success;
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file desriptor, then
+// calls _exit(1).
+void ForkingDeathTest::Abort(AbortReason reason) {
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char flag =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
+ GTEST_DEATH_TEST_CHECK_SYSCALL(write(write_fd_, &flag, 1));
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(write_fd_));
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+ NoExecDeathTest(const char* statement, const RE* regex) :
+ ForkingDeathTest(statement, regex) { }
+ virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG(WARNING, DeathTestThreadWarning(thread_count));
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1);
+
+ last_death_test_message = "";
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_forked(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+ ExecDeathTest(const char* statement, const RE* regex,
+ const char* file, int line) :
+ ForkingDeathTest(statement, regex), file_(file), line_(line) { }
+ virtual TestRole AssumeRole();
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin();
+ i + 1 != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, strdup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, strdup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+// The main function for a threadsafe-style death test child process.
+static int ExecDeathTestChildMain(void* child_arg) {
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(args->close_fd));
+ execve(args->argv[0], args->argv, environ);
+ DeathTestAbort("execve failed: %s", strerror(errno));
+ return EXIT_FAILURE;
+}
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+static bool StackLowerThanAddress(const void* ptr) {
+ int dummy;
+ return &dummy < ptr;
+}
+
+static bool StackGrowsDown() {
+ int dummy;
+ return StackLowerThanAddress(&dummy);
+}
+
+// A threadsafe implementation of fork(2) for threadsafe-style death tests
+// that uses clone(2). It dies with an error message if anything goes
+// wrong.
+static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = getpagesize();
+ void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK(stack != MAP_FAILED);
+ void* const stack_top =
+ static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+ ExecDeathTestArgs args = { argv, close_fd };
+ const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top,
+ SIGCHLD, &args);
+ GTEST_DEATH_TEST_CHECK(child_pid != -1);
+ GTEST_DEATH_TEST_CHECK(munmap(stack, stack_size) != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ set_write_fd(flag->status_fd);
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const String filter_flag =
+ String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX, kFilterFlag,
+ info->test_case_name(), info->name());
+ const String internal_flag =
+ String::Format("--%s%s=%s:%d:%d:%d",
+ GTEST_FLAG_PREFIX, kInternalRunDeathTestFlag, file_, line_,
+ death_test_index, pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvs());
+ args.AddArgument("--logtostderr");
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ last_death_test_message = "";
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_forked(true);
+ return OVERSEE_TEST;
+}
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+ const char* file, int line,
+ DeathTest** test) {
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != NULL) {
+ if (death_test_index > flag->index) {
+ last_death_test_message = String::Format(
+ "Death test count (%d) somehow exceeded expected maximum (%d)",
+ death_test_index, flag->index);
+ return false;
+ }
+
+ if (!(flag->file == file && flag->line == line &&
+ flag->index == death_test_index)) {
+ *test = NULL;
+ return true;
+ }
+ }
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, regex, file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, regex);
+ } else {
+ last_death_test_message = String::Format(
+ "Unknown death test style \"%s\" encountered",
+ GTEST_FLAG(death_test_style).c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (true) {
+ const ::std::string::size_type colon = str.find(':', pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+// Attempts to parse a string into a positive integer. Returns true
+// if that is possible. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static bool ParsePositiveInt(const ::std::string& str, int* number) {
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtol's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !isdigit(str[0])) {
+ return false;
+ }
+ char* endptr;
+ const long parsed = strtol(str.c_str(), &endptr, 10); // NOLINT
+ if (*endptr == '\0' && parsed <= INT_MAX) {
+ *number = static_cast<int>(parsed);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+ if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+ InternalRunDeathTestFlag* const internal_run_death_test_flag =
+ new InternalRunDeathTestFlag;
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), ':', &fields);
+ if (fields.size() != 4
+ || !ParsePositiveInt(fields[1], &internal_run_death_test_flag->line)
+ || !ParsePositiveInt(fields[2], &internal_run_death_test_flag->index)
+ || !ParsePositiveInt(fields[3],
+ &internal_run_death_test_flag->status_fd)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str());
+ }
+ internal_run_death_test_flag->file = fields[0].c_str();
+ return internal_run_death_test_flag;
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
diff --git a/src/gtest/gtest-death-test.h b/src/gtest/gtest-death-test.h
new file mode 100644
index 00000000..cbd41fe6
--- /dev/null
+++ b/src/gtest/gtest-death-test.h
@@ -0,0 +1,205 @@
+// 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: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include <gtest/internal/gtest-death-test-internal.h>
+
+namespace testing {
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string(death_test_style);
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. The assertion fails immediately if there are more than one
+// active threads. This is because it's safe to fork() only when
+// there is a single thread.
+//
+// 2. The parent process forks a sub-process and runs the death test
+// in it; the sub-process exits with code 0 at the end of the death
+// test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Note:
+//
+// It's not safe to call exit() if the current process is forked from
+// a multi-threaded process, so people usually call _exit() instead in
+// such a case. However, we are not concerned with this as we run
+// death tests only when there is a single thread. Since exit() has a
+// cleaner semantics (it also calls functions registered with atexit()
+// and on_exit()), this macro calls exit() instead of _exit() to
+// terminate the child process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i);
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+#define ASSERT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST(statement, predicate, regex, GTEST_FATAL_FAILURE)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST(statement, predicate, regex, GTEST_NONFATAL_FAILURE)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+#define ASSERT_DEATH(statement, regex) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_DEATH(statement, regex) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class ExitedWithCode {
+ public:
+ explicit ExitedWithCode(int exit_code);
+ bool operator()(int exit_status) const;
+ private:
+ const int exit_code_;
+};
+
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class KilledBySignal {
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+#ifdef NDEBUG
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (false)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (false)
+
+#else
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+#endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/src/gtest/gtest-filepath.cc b/src/gtest/gtest-filepath.cc
new file mode 100644
index 00000000..2fba96ea
--- /dev/null
+++ b/src/gtest/gtest-filepath.cc
@@ -0,0 +1,208 @@
+// 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.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-port.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#include <io.h>
+#endif // _WIN32
+
+#include <sys/stat.h>
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+#ifdef GTEST_OS_WINDOWS
+const char kPathSeparator = '\\';
+const char kPathSeparatorString[] = "\\";
+const char kCurrentDirectoryString[] = ".\\";
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+ String dot_extension(String::Format(".%s", extension));
+ if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
+ return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4));
+ }
+ return *this;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+ return last_sep ? FilePath(String(last_sep + 1)) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+ return FilePath(last_sep ? String(c_str(), last_sep + 1 - c_str())
+ : String(kCurrentDirectoryString));
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension) {
+ FilePath dir(directory.RemoveTrailingPathSeparator());
+ if (number == 0) {
+ return FilePath(String::Format("%s%c%s.%s", dir.c_str(), kPathSeparator,
+ base_name.c_str(), extension));
+ }
+ return FilePath(String::Format("%s%c%s_%d.%s", dir.c_str(), kPathSeparator,
+ base_name.c_str(), number, extension));
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#ifdef GTEST_OS_WINDOWS
+ struct _stat file_stat = {};
+ return _stat(pathname_.c_str(), &file_stat) == 0;
+#else
+ struct stat file_stat = {};
+ return stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+ bool result = false;
+#ifdef _WIN32
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ struct _stat file_stat = {};
+ result = _stat(removed_sep.c_str(), &file_stat) == 0 &&
+ (_S_IFDIR & file_stat.st_mode) != 0;
+#else
+ struct stat file_stat = {};
+ result = stat(pathname_.c_str(), &file_stat) == 0 &&
+ S_ISDIR(file_stat.st_mode);
+#endif // _WIN32
+ return result;
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension) {
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+ return pathname_.EndsWith(kPathSeparatorString);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.GetLength() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#ifdef _WIN32
+ int result = _mkdir(pathname_.c_str());
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // _WIN32
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+ return pathname_.EndsWith(kPathSeparatorString)
+ ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1))
+ : *this;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/src/gtest/gtest-internal-inl.h b/src/gtest/gtest-internal-inl.h
new file mode 100644
index 00000000..2a7d71cb
--- /dev/null
+++ b/src/gtest/gtest-internal-inl.h
@@ -0,0 +1,1118 @@
+// 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.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION is defined iff the current translation unit is
+// part of Google Test's implementation.
+#ifndef GTEST_IMPLEMENTATION
+// A user is trying to include this from his code - just say no.
+#error "gtest-internal-inl.h is part of Google Test's internal implementation."
+#error "It must not be included except by Google Test itself."
+#endif // GTEST_IMPLEMENTATION
+
+#include <stddef.h>
+
+#include <gtest/internal/gtest-port.h>
+
+#ifdef GTEST_OS_WINDOWS
+#include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+#include <ostream> // NOLINT
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify these flags in the code, but want
+// Google Test's own unit tests to be able to access them. Therefore we
+// declare them here as opposed to in gtest.h.
+GTEST_DECLARE_bool(break_on_failure);
+GTEST_DECLARE_bool(catch_exceptions);
+GTEST_DECLARE_string(color);
+GTEST_DECLARE_string(filter);
+GTEST_DECLARE_bool(list_tests);
+GTEST_DECLARE_string(output);
+GTEST_DECLARE_int32(repeat);
+GTEST_DECLARE_int32(stack_trace_depth);
+GTEST_DECLARE_bool(show_internal_stack_frames);
+
+namespace internal {
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kColorFlag[] = "color";
+const char kRepeatFlag[] = "repeat";
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ repeat_ = GTEST_FLAG(repeat);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(repeat) = repeat_;
+ }
+ private:
+ // Fields for saving the original values of flags.
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ String color_;
+ String death_test_style_;
+ String filter_;
+ String internal_run_death_test_;
+ bool list_tests_;
+ String output_;
+ bool pretty_;
+ internal::Int32 repeat_;
+} GTEST_ATTRIBUTE_UNUSED;
+
+// Converts a Unicode code-point to its UTF-8 encoding.
+String ToUtf8String(wchar_t wchar);
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount();
+
+// List is a simple singly-linked list container.
+//
+// We cannot use std::list as Microsoft's implementation of STL has
+// problems when exception is disabled. There is a hack to work
+// around this, but we've seen cases where the hack fails to work.
+//
+// TODO(wan): switch to std::list when we have a reliable fix for the
+// STL problem, e.g. when we upgrade to the next version of Visual
+// C++, or (more likely) switch to STLport.
+//
+// The element type must support copy constructor.
+
+// Forward declare List
+template <typename E> // E is the element type.
+class List;
+
+// ListNode is a node in a singly-linked list. It consists of an
+// element and a pointer to the next node. The last node in the list
+// has a NULL value for its next pointer.
+template <typename E> // E is the element type.
+class ListNode {
+ friend class List<E>;
+
+ private:
+
+ E element_;
+ ListNode * next_;
+
+ // The c'tor is private s.t. only in the ListNode class and in its
+ // friend class List we can create a ListNode object.
+ //
+ // Creates a node with a given element value. The next pointer is
+ // set to NULL.
+ //
+ // ListNode does NOT have a default constructor. Always use this
+ // constructor (with parameter) to create a ListNode object.
+ explicit ListNode(const E & element) : element_(element), next_(NULL) {}
+
+ // We disallow copying ListNode
+ GTEST_DISALLOW_COPY_AND_ASSIGN(ListNode);
+
+ public:
+
+ // Gets the element in this node.
+ E & element() { return element_; }
+ const E & element() const { return element_; }
+
+ // Gets the next node in the list.
+ ListNode * next() { return next_; }
+ const ListNode * next() const { return next_; }
+};
+
+
+// List is a simple singly-linked list container.
+template <typename E> // E is the element type.
+class List {
+ public:
+
+ // Creates an empty list.
+ List() : head_(NULL), last_(NULL), size_(0) {}
+
+ // D'tor.
+ virtual ~List();
+
+ // Clears the list.
+ void Clear() {
+ if ( size_ > 0 ) {
+ // 1. Deletes every node.
+ ListNode<E> * node = head_;
+ ListNode<E> * next = node->next();
+ for ( ; ; ) {
+ delete node;
+ node = next;
+ if ( node == NULL ) break;
+ next = node->next();
+ }
+
+ // 2. Resets the member variables.
+ head_ = last_ = NULL;
+ size_ = 0;
+ }
+ }
+
+ // Gets the number of elements.
+ int size() const { return size_; }
+
+ // Returns true if the list is empty.
+ bool IsEmpty() const { return size() == 0; }
+
+ // Gets the first element of the list, or NULL if the list is empty.
+ ListNode<E> * Head() { return head_; }
+ const ListNode<E> * Head() const { return head_; }
+
+ // Gets the last element of the list, or NULL if the list is empty.
+ ListNode<E> * Last() { return last_; }
+ const ListNode<E> * Last() const { return last_; }
+
+ // Adds an element to the end of the list. A copy of the element is
+ // created using the copy constructor, and then stored in the list.
+ // Changes made to the element in the list doesn't affect the source
+ // object, and vice versa.
+ void PushBack(const E & element) {
+ ListNode<E> * new_node = new ListNode<E>(element);
+
+ if ( size_ == 0 ) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ last_->next_ = new_node;
+ last_ = new_node;
+ size_++;
+ }
+ }
+
+ // Adds an element to the beginning of this list.
+ void PushFront(const E& element) {
+ ListNode<E>* const new_node = new ListNode<E>(element);
+
+ if ( size_ == 0 ) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ new_node->next_ = head_;
+ head_ = new_node;
+ size_++;
+ }
+ }
+
+ // Removes an element from the beginning of this list. If the
+ // result argument is not NULL, the removed element is stored in the
+ // memory it points to. Otherwise the element is thrown away.
+ // Returns true iff the list wasn't empty before the operation.
+ bool PopFront(E* result) {
+ if (size_ == 0) return false;
+
+ if (result != NULL) {
+ *result = head_->element_;
+ }
+
+ ListNode<E>* const old_head = head_;
+ size_--;
+ if (size_ == 0) {
+ head_ = last_ = NULL;
+ } else {
+ head_ = head_->next_;
+ }
+ delete old_head;
+
+ return true;
+ }
+
+ // Inserts an element after a given node in the list. It's the
+ // caller's responsibility to ensure that the given node is in the
+ // list. If the given node is NULL, inserts the element at the
+ // front of the list.
+ ListNode<E>* InsertAfter(ListNode<E>* node, const E& element) {
+ if (node == NULL) {
+ PushFront(element);
+ return Head();
+ }
+
+ ListNode<E>* const new_node = new ListNode<E>(element);
+ new_node->next_ = node->next_;
+ node->next_ = new_node;
+ size_++;
+ if (node == last_) {
+ last_ = new_node;
+ }
+
+ return new_node;
+ }
+
+ // Returns the number of elements that satisfy a given predicate.
+ // The parameter 'predicate' is a Boolean function or functor that
+ // accepts a 'const E &', where E is the element type.
+ template <typename P> // P is the type of the predicate function/functor
+ int CountIf(P predicate) const {
+ int count = 0;
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element()) ) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ // Applies a function/functor to each element in the list. The
+ // parameter 'functor' is a function/functor that accepts a 'const
+ // E &', where E is the element type. This method does not change
+ // the elements.
+ template <typename F> // F is the type of the function/functor
+ void ForEach(F functor) const {
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ functor(node->element());
+ }
+ }
+
+ // Returns the first node whose element satisfies a given predicate,
+ // or NULL if none is found. The parameter 'predicate' is a
+ // function/functor that accepts a 'const E &', where E is the
+ // element type. This method does not change the elements.
+ template <typename P> // P is the type of the predicate function/functor.
+ const ListNode<E> * FindIf(P predicate) const {
+ for ( const ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element()) ) {
+ return node;
+ }
+ }
+
+ return NULL;
+ }
+
+ template <typename P>
+ ListNode<E> * FindIf(P predicate) {
+ for ( ListNode<E> * node = Head();
+ node != NULL;
+ node = node->next() ) {
+ if ( predicate(node->element() ) ) {
+ return node;
+ }
+ }
+
+ return NULL;
+ }
+
+ private:
+ ListNode<E>* head_; // The first node of the list.
+ ListNode<E>* last_; // The last node of the list.
+ int size_; // The number of elements in the list.
+
+ // We disallow copying List.
+ GTEST_DISALLOW_COPY_AND_ASSIGN(List);
+};
+
+// The virtual destructor of List.
+template <typename E>
+List<E>::~List() {
+ Clear();
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T * x) {
+ delete x;
+}
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const char* key, const char* value) :
+ key_(key), value_(value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const char* new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ String key_;
+ // The value supplied by the user.
+ String value_;
+};
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const char* key)
+ : key_(key) {}
+
+ // Returns true iff the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return String(test_property.key()).Compare(key_) == 0;
+ }
+
+ private:
+ String key_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class TestResult {
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the list of TestPartResults.
+ const internal::List<TestPartResult> & test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the list of TestProperties.
+ const internal::List<internal::TestProperty> & test_properties() const {
+ return test_properties_;
+ }
+
+ // Gets the number of successful test parts.
+ int successful_part_count() const;
+
+ // Gets the number of failed test parts.
+ int failed_part_count() const;
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns true iff the test passed (i.e. no test part failed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test failed.
+ bool Failed() const { return failed_part_count() > 0; }
+
+ // Returns true iff the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key.
+ void RecordProperty(const internal::TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testcase tags. Returns true if the property is valid.
+ // TODO(russr): Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const internal::TestProperty& test_property);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the object.
+ void Clear();
+ private:
+ // Protects mutable state of the property list and of owned properties, whose
+ // values may be updated.
+ internal::Mutex test_properites_mutex_;
+
+ // The list of TestPartResults
+ internal::List<TestPartResult> test_part_results_;
+ // The list of TestProperties
+ internal::List<internal::TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN(TestResult);
+}; // class TestResult
+
+class TestInfoImpl {
+ public:
+ TestInfoImpl(TestInfo* parent, const char* test_case_name,
+ const char* name, TypeId fixture_class_id,
+ TestMaker maker);
+ ~TestInfoImpl();
+
+ // Returns true if this test should run.
+ bool should_run() const { return should_run_; }
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Returns true if this test is disabled. Disabled tests are not run.
+ bool is_disabled() const { return is_disabled_; }
+
+ // Sets the is_disabled member.
+ void set_is_disabled(bool is) { is_disabled_ = is; }
+
+ // Returns the test case name.
+ const char* test_case_name() const { return test_case_name_.c_str(); }
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the ID of the test fixture class.
+ TypeId fixture_class_id() const { return fixture_class_id_; }
+
+ // Returns the test result.
+ internal::TestResult* result() { return &result_; }
+ const internal::TestResult* result() const { return &result_; }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ // Calls the given TestInfo object's Run() method.
+ static void RunTest(TestInfo * test_info) {
+ test_info->impl()->Run();
+ }
+
+ // Clears the test result.
+ void ClearResult() { result_.Clear(); }
+
+ // Clears the test result in the given TestInfo object.
+ static void ClearTestResult(TestInfo * test_info) {
+ test_info->impl()->ClearResult();
+ }
+
+ private:
+ // These fields are immutable properties of the test.
+ TestInfo* const parent_; // The owner of this object
+ const String test_case_name_; // Test case name
+ const String name_; // Test name
+ const TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True iff this test should run
+ bool is_disabled_; // True iff this test is disabled
+ const TestMaker maker_; // The function that creates the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ internal::TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(TestInfoImpl);
+};
+
+} // namespace internal
+
+// A test case, which consists of a list of TestInfos.
+//
+// TestCase is not copyable.
+class TestCase {
+ public:
+ // Creates a TestCase with the given name.
+ //
+ // TestCase does NOT have a default constructor. Always use this
+ // constructor to create a TestCase object.
+ //
+ // Arguments:
+ //
+ // name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase(const char* name,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Destructor of TestCase.
+ virtual ~TestCase();
+
+ // Gets the name of the TestCase.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns true if any test in this test case should run.
+ bool should_run() const { return should_run_; }
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Gets the (mutable) list of TestInfos in this TestCase.
+ internal::List<TestInfo*>& test_info_list() { return *test_info_list_; }
+
+ // Gets the (immutable) list of TestInfos in this TestCase.
+ const internal::List<TestInfo *> & test_info_list() const {
+ return *test_info_list_;
+ }
+
+ // Gets the number of successful tests in this test case.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests in this test case.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests in this test case.
+ int disabled_test_count() const;
+
+ // Get the number of tests in this test case that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test case.
+ int total_test_count() const;
+
+ // Returns true iff the test case passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test case failed.
+ bool Failed() const { return failed_test_count() > 0; }
+
+ // Returns the elapsed time, in milliseconds.
+ internal::TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Adds a TestInfo to this test case. Will delete the TestInfo upon
+ // destruction of the TestCase object.
+ void AddTestInfo(TestInfo * test_info);
+
+ // Finds and returns a TestInfo with the given name. If one doesn't
+ // exist, returns NULL.
+ TestInfo* GetTestInfo(const char* test_name);
+
+ // Clears the results of all tests in this test case.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test case.
+ static void ClearTestCaseResult(TestCase* test_case) {
+ test_case->ClearResult();
+ }
+
+ // Runs every test in this TestCase.
+ void Run();
+
+ // Runs every test in the given TestCase.
+ static void RunTestCase(TestCase * test_case) { test_case->Run(); }
+
+ // Returns true iff test passed.
+ static bool TestPassed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Passed();
+ }
+
+ // Returns true iff test failed.
+ static bool TestFailed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Failed();
+ }
+
+ // Returns true iff test is disabled.
+ static bool TestDisabled(const TestInfo * test_info) {
+ return test_info->impl()->is_disabled();
+ }
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo *test_info) {
+ return test_info->impl()->should_run();
+ }
+
+ private:
+ // Name of the test case.
+ internal::String name_;
+ // List of TestInfos.
+ internal::List<TestInfo*>* test_info_list_;
+ // Pointer to the function that sets up the test case.
+ Test::SetUpTestCaseFunc set_up_tc_;
+ // Pointer to the function that tears down the test case.
+ Test::TearDownTestCaseFunc tear_down_tc_;
+ // True iff any test in this test case should run.
+ bool should_run_;
+ // Elapsed time, in milliseconds.
+ internal::TimeInMillis elapsed_time_;
+
+ // We disallow copying TestCases.
+ GTEST_DISALLOW_COPY_AND_ASSIGN(TestCase);
+};
+
+namespace internal {
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class UnitTestOptions {
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static String GetOutputFormat();
+
+ // Returns the name of the requested output file, or the default if none
+ // was explicitly specified.
+ static String GetOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true iff the wildcard pattern matches the string. The
+ // first ':' or '\0' character in pattern marks the end of it.
+ //
+ // This recursive algorithm isn't very efficient, but is clear and
+ // works well enough for matching test names, which are short.
+ static bool PatternMatchesString(const char *pattern, const char *str);
+
+ // Returns true iff the user-specified filter matches the test case
+ // name and the test name.
+ static bool FilterMatchesTest(const String &test_case_name,
+ const String &test_name);
+
+#ifdef GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+ private:
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const String& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as a String. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetterInterface);
+};
+
+// A working implemenation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() {}
+ virtual String CurrentStackTrace(int max_depth, int skip_count);
+ virtual void UponLeavingGTest();
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ Mutex mutex_; // protects all internal state
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to CurrentStackTrace() from within the user code.
+ void* caller_frame_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ String message;
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class UnitTestImpl : public TestPartResultReporterInterface {
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // Reports a test part result. This method is from the
+ // TestPartResultReporterInterface interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ // Returns the current test part result reporter.
+ TestPartResultReporterInterface* test_part_result_reporter();
+
+ // Sets the current test part result reporter.
+ void set_test_part_result_reporter(TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ internal::TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const internal::TestResult* ad_hoc_test_result() const {
+ return &ad_hoc_test_result_;
+ }
+
+ // Sets the unit test result printer.
+ //
+ // Does nothing if the input and the current printer object are the
+ // same; otherwise, deletes the old printer object and makes the
+ // input the current printer.
+ void set_result_printer(UnitTestEventListenerInterface * result_printer);
+
+ // Returns the current unit test result printer if it is not NULL;
+ // otherwise, creates an appropriate result printer, makes it the
+ // current printer, and returns it.
+ UnitTestEventListenerInterface* result_printer();
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as a String.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ String CurrentOsStackTraceExceptTop(int skip_count);
+
+ // Finds and returns a TestCase with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase* GetTestCase(const char* test_case_name,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // test_info: the TestInfo object
+ void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestInfo * test_info) {
+ GetTestCase(test_info->test_case_name(),
+ set_up_tc,
+ tear_down_tc)->AddTestInfo(test_info);
+ }
+
+ // Sets the TestCase object for the test that's currently running.
+ void set_current_test_case(TestCase* current_test_case) {
+ current_test_case_ = current_test_case;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* current_test_info) {
+ current_test_info_ = current_test_info;
+ }
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns 0 if all tests are successful, or 1 otherwise. If any
+ // exception is thrown during a test on Windows, this test is
+ // considered to be failed, but the rest of the tests will still be
+ // run. (We disable exceptions on Linux and Mac OS X, so the issue
+ // doesn't apply there.)
+ int RunAllTests();
+
+ // Clears the results of all tests, including the ad hoc test.
+ void ClearResult() {
+ test_cases_.ForEach(TestCase::ClearTestCaseResult);
+ ad_hoc_test_result_.Clear();
+ }
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestCase and TestInfo object.
+ // Returns the number of tests that should run.
+ int FilterTests();
+
+ // Lists all the tests by name.
+ void ListAllTests();
+
+ const TestCase* current_test_case() const { return current_test_case_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the list of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ internal::List<Environment*>* environments() { return &environments_; }
+ internal::List<Environment*>* environments_in_reverse_order() {
+ return &environments_in_reverse_order_;
+ }
+
+ internal::List<TestCase*>* test_cases() { return &test_cases_; }
+ const internal::List<TestCase*>* test_cases() const { return &test_cases_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ internal::List<TraceInfo>* gtest_trace_stack() {
+ return gtest_trace_stack_.pointer();
+ }
+ const internal::List<TraceInfo>* gtest_trace_stack() const {
+ return gtest_trace_stack_.pointer();
+ }
+
+#ifdef GTEST_HAS_DEATH_TEST
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ private:
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // Points to (but doesn't own) the test part result reporter.
+ TestPartResultReporterInterface* test_part_result_reporter_;
+
+ // The list of environments that need to be set-up/torn-down
+ // before/after the tests are run. environments_in_reverse_order_
+ // simply mirrors environments_ in reverse order.
+ internal::List<Environment*> environments_;
+ internal::List<Environment*> environments_in_reverse_order_;
+
+ internal::List<TestCase*> test_cases_; // The list of TestCases.
+
+ // Points to the last death test case registered. Initially NULL.
+ internal::ListNode<TestCase*>* last_death_test_case_;
+
+ // This points to the TestCase for the currently running test. It
+ // changes as Google Test goes through one test case after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initally NULL.
+ TestCase* current_test_case_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ internal::TestResult ad_hoc_test_result_;
+
+ // The unit test result printer. Will be deleted when the UnitTest
+ // object is destructed. By default, a plain text printer is used,
+ // but the user can set this field to use a custom printer if that
+ // is desired.
+ UnitTestEventListenerInterface* result_printer_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#ifdef GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<internal::List<TraceInfo> > gtest_trace_stack_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+ return UnitTest::GetInstance()->impl();
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/src/gtest/gtest-message.h b/src/gtest/gtest-message.h
new file mode 100644
index 00000000..746a1685
--- /dev/null
+++ b/src/gtest/gtest-message.h
@@ -0,0 +1,236 @@
+// 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: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-string.h" // NOLINT
+#include "gtest-internal.h" // NOLINT
+#else
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-internal.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a StrStream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that StrStream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class Message {
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ // We allocate the StrStream separately because it otherwise each use of
+ // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+ // stack frame leading to huge stack frames in some cases; gcc does not reuse
+ // the stack space.
+ Message() : ss_(new internal::StrStream) {}
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new internal::StrStream) {
+ *ss_ << str;
+ }
+
+ ~Message() { delete ss_; }
+#ifdef __SYMBIAN32__
+ // Streams a value (either a pointer or not) to this object.
+ template <typename T>
+ inline Message& operator <<(const T& value) {
+ StreamHelper(typename internal::is_pointer<T>::type(), value);
+ return *this;
+ }
+#else
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ ::GTestStreamToHelper(ss_, val);
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ return *this;
+ }
+#endif // __SYMBIAN32__
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+ Message& operator <<(wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::wstring& wstr);
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+ // Gets the text streamed to this object so far as a String.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::String GetString() const {
+ return internal::StrStreamToString(ss_);
+ }
+
+ private:
+#ifdef __SYMBIAN32__
+ // These are needed as the Nokia Symbian Compiler cannot decide between
+ // const T& and const T* in a function template. The Nokia compiler _can_
+ // decide between class template specializations for T and T*, so a
+ // tr1::type_traits-like is_pointer works, and we can overload on that.
+ template <typename T>
+ inline void StreamHelper(internal::true_type dummy, T* pointer) {
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ }
+ template <typename T>
+ inline void StreamHelper(internal::false_type dummy, const T& value) {
+ ::GTestStreamToHelper(ss_, value);
+ }
+#endif // __SYMBIAN32__
+
+ // We'll hold the text streamed to this object here.
+ internal::StrStream* const ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+ return os << sb.GetString();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/src/gtest/gtest-port.cc b/src/gtest/gtest-port.cc
new file mode 100644
index 00000000..5c126149
--- /dev/null
+++ b/src/gtest/gtest-port.cc
@@ -0,0 +1,292 @@
+// 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.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/internal/gtest-port.h>
+
+#include <limits.h>
+#ifdef GTEST_HAS_DEATH_TEST
+#include <regex.h>
+#endif // GTEST_HAS_DEATH_TEST
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE() {
+ regfree(&regex_);
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff str contains regular expression re.
+bool RE::PartialMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = strdup(regex);
+ is_valid_ = regcomp(&regex_, regex, REG_EXTENDED) == 0;
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Logs a message at the given severity level.
+void GTestLog(GTestLogSeverity severity, const char* file,
+ int line, const char* msg) {
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
+ if (severity == GTEST_FATAL) {
+ abort();
+ }
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Defines the stderr capturer.
+
+class CapturedStderr {
+ public:
+ // The ctor redirects stderr to a temporary file.
+ CapturedStderr() {
+ uncaptured_fd_ = dup(STDERR_FILENO);
+
+ char name_template[] = "captured_stderr.XXXXXX";
+ const int captured_fd = mkstemp(name_template);
+ filename_ = name_template;
+ fflush(NULL);
+ dup2(captured_fd, STDERR_FILENO);
+ close(captured_fd);
+ }
+
+ ~CapturedStderr() {
+ remove(filename_.c_str());
+ }
+
+ // Stops redirecting stderr.
+ void StopCapture() {
+ // Restores the original stream.
+ fflush(NULL);
+ dup2(uncaptured_fd_, STDERR_FILENO);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ // Returns the name of the temporary file holding the stderr output.
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ ::std::string filename() const { return filename_; }
+
+ private:
+ int uncaptured_fd_;
+ ::std::string filename_;
+};
+
+static CapturedStderr* g_captured_stderr = NULL;
+
+// Returns the size (in bytes) of a file.
+static size_t GetFileSize(FILE * file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
+// use it here.
+static ::std::string ReadEntireFile(FILE * file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const ::std::string content(buffer, buffer+bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+ if (g_captured_stderr != NULL) {
+ GTEST_LOG(FATAL, "Only one stderr capturer can exist at one time.");
+ }
+ g_captured_stderr = new CapturedStderr;
+}
+
+// Stops capturing stderr and returns the captured string.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
+// use it here.
+::std::string GetCapturedStderr() {
+ g_captured_stderr->StopCapture();
+ FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r");
+ const ::std::string content = ReadEntireFile(file);
+ fclose(file);
+
+ delete g_captured_stderr;
+ g_captured_stderr = NULL;
+
+ return content;
+}
+
+// A copy of all command line arguments. Set by ParseGTestFlags().
+::std::vector<String> g_argvs;
+
+// Returns the command line as a vector of strings.
+const ::std::vector<String>& GetArgvs() { return g_argvs; }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static String FlagToEnvVar(const char* flag) {
+ const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString();
+
+ Message env_var;
+ for (int i = 0; i != full_flag.GetLength(); i++) {
+ env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
+ }
+
+ return env_var.GetString();
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = GetEnv(env_var.c_str());
+ return string_value == NULL ?
+ default_value : strcmp(string_value, "0") != 0;
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = NULL;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an Int32?
+ const Int32 result = static_cast<Int32>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an Int32.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = GetEnv(env_var.c_str());
+ if (string_value == NULL) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ Int32 result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const value = GetEnv(env_var.c_str());
+ return value == NULL ? default_value : value;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/src/gtest/gtest-spi.h b/src/gtest/gtest-spi.h
new file mode 100644
index 00000000..75d0dcf2
--- /dev/null
+++ b/src/gtest/gtest-spi.h
@@ -0,0 +1,247 @@
+// Copyright 2007, 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: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <gtest/gtest.h>
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class TestPartResult {
+ public:
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(TestPartResultType type,
+ const char* file_name,
+ int line_number,
+ const char* message)
+ : type_(type),
+ file_name_(file_name),
+ line_number_(line_number),
+ message_(message) {
+ }
+
+ // Gets the outcome of the test part.
+ TestPartResultType type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const { return file_name_.c_str(); }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true iff the test part passed.
+ bool passed() const { return type_ == TPRT_SUCCESS; }
+
+ // Returns true iff the test part failed.
+ bool failed() const { return type_ != TPRT_SUCCESS; }
+
+ // Returns true iff the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == TPRT_NONFATAL_FAILURE; }
+
+ // Returns true iff the test part fatally failed.
+ bool fatally_failed() const { return type_ == TPRT_FATAL_FAILURE; }
+ private:
+ TestPartResultType type_;
+
+ // The name of the source file where the test part took place, or
+ // NULL if the source file is unknown.
+ internal::String file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ internal::String message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// We define this class as we cannot use STL containers when compiling
+// Google Test with MSVC 7.1 and exceptions disabled.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class TestPartResultArray {
+ public:
+ TestPartResultArray();
+ ~TestPartResultArray();
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+ private:
+ // Internally we use a list to simulate the array. Yes, this means
+ // that random access is O(N) in time, but it's OK for its purpose.
+ internal::List<TestPartResult>* const list_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a
+// Google Test failure is reported.
+class ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results.
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ virtual ~ScopedFakeTestPartResultReporter();
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+ TestPartResultReporterInterface* const old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class SingleFailureChecker {
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResultType type,
+ const char* substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResultType type_;
+ const String substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// Implementation note: The verification is done in the destructor of
+// SingleFailureChecker, to make sure that it's done even when
+// 'statement' throws an exception.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+#define EXPECT_FATAL_FAILURE(statement, substr) do {\
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (false)
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with
+// 'substr' being part of the failure message.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// Implementation note: The verification is done in the destructor of
+// SingleFailureChecker, to make sure that it's done even when
+// 'statement' throws an exception or aborts the function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ &gtest_failures);\
+ statement;\
+ }\
+ } while (false)
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/src/gtest/gtest.cc b/src/gtest/gtest.cc
new file mode 100644
index 00000000..1eee3922
--- /dev/null
+++ b/src/gtest/gtest.cc
@@ -0,0 +1,3546 @@
+// 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: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef GTEST_OS_LINUX
+
+// TODO(kenton): Use autoconf to detect availability of gettimeofday().
+#define HAS_GETTIMEOFDAY
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+// Declares vsnprintf(). This header is not available on Windows.
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#elif defined(_WIN32_WCE) // We are on Windows CE.
+
+#include <windows.h> // NOLINT
+
+#elif defined(_WIN32) // We are on Windows proper.
+
+#include <io.h> // NOLINT
+#include <sys/timeb.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#include <sys/stat.h> // NOLINT
+
+#if defined(__MINGW__) || defined(__MINGW32__)
+// MinGW has gettimeofday() but not _ftime64()
+// TODO(kenton): Use autoconf to detect availability of gettimeofday().
+// TODO(kenton): There are other ways to get the time on Windows, like
+// GetTickCount() or GetSystemTimeAsFileTime(). MinGW supports these.
+// consider using them instead.
+#define HAS_GETTIMEOFDAY
+#include <sys/time.h> // NOLINT
+#endif
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <windows.h> // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton): Use autoconf to detect availability of gettimeofday().
+#define HAS_GETTIMEOFDAY
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <sys/time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION
+#include <gtest/gtest-internal-inl.h>
+#undef GTEST_IMPLEMENTATION
+
+#ifdef GTEST_OS_WINDOWS
+#define fileno _fileno
+#define isatty _isatty
+#define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+namespace testing {
+
+// Constants.
+
+// A test that matches this pattern is disabled and not run.
+static const char kDisableTestPattern[] = "DISABLED_*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+GTEST_DEFINE_bool(
+ break_on_failure,
+ internal::BoolFromGTestEnv("break_on_failure", false),
+ "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool(
+ catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", false),
+ "True iff " GTEST_NAME
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to xterm or xterm-color.");
+
+GTEST_DEFINE_string(
+ filter,
+ internal::StringFromGTestEnv("filter", kUniversalFilter),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool(list_tests, false,
+ "List all tests without running them.");
+
+GTEST_DEFINE_string(
+ output,
+ internal::StringFromGTestEnv("output", ""),
+ "A format (currently must be \"xml\"), optionally followed "
+ "by a colon and an output file name or directory. A directory "
+ "is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_int32(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_int32(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_bool(
+ show_internal_stack_frames, false,
+ "True iff " GTEST_NAME " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+namespace internal {
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+
+// A user must call testing::ParseGTestFlags() to initialize Google
+// Test. g_parse_gtest_flags_called is set to true iff
+// ParseGTestFlags() has been called. We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+static bool g_parse_gtest_flags_called = false;
+static bool GTestIsInitialized() { return g_parse_gtest_flags_called; }
+
+// Iterates over a list of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const internal::List<TestCase*>& case_list,
+ int (TestCase::*method)() const) {
+ int sum = 0;
+ for (const internal::ListNode<TestCase*>* node = case_list.Head();
+ node != NULL;
+ node = node->next()) {
+ sum += (node->element()->*method)();
+ }
+ return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+ return test_case->should_run();
+}
+
+#ifdef _WIN32_WCE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+static void abort() {
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+#endif // _WIN32_WCE
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResultType type, const char* file,
+ int line, const char* message)
+ : type_(type), file_(file), line_(line), message_(message) {
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+ UnitTest::GetInstance()->
+ AddTestPartResult(type_, file_, line_,
+ AppendUserMessage(message_, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+// Application pathname gotten in ParseGTestFlags.
+String g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if defined(_WIN32_WCE) || defined(_WIN32)
+ result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(g_executable_path));
+#endif // _WIN32_WCE || _WIN32
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+String UnitTestOptions::GetOutputFormat() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL) return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == NULL) ?
+ String(gtest_output_flag) :
+ String(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+String UnitTestOptions::GetOutputFile() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL)
+ return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == NULL)
+ return String(kDefaultOutputFile);
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsDirectory())
+ return output_name.ToString();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.ToString();
+}
+
+// Returns true iff the wildcard pattern matches the string. The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+ const char *str) {
+ switch (*pattern) {
+ case '\0':
+ case ':': // Either ':' or '\0' marks the end of the pattern.
+ return *str == '\0';
+ case '?': // Matches any single character.
+ return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+ case '*': // Matches any string (possibly empty) of characters.
+ return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: // Non-special character. Matches itself.
+ return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
+ }
+}
+
+bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
+ const char *cur_pattern = filter;
+ while (true) {
+ if (PatternMatchesString(cur_pattern, name.c_str())) {
+ return true;
+ }
+
+ // Finds the next pattern in the filter.
+ cur_pattern = strchr(cur_pattern, ':');
+
+ // Returns if no more pattern can be found.
+ if (cur_pattern == NULL) {
+ return false;
+ }
+
+ // Skips the pattern separater (the ':' character).
+ cur_pattern++;
+ }
+}
+
+// TODO(keithray): move String function implementations to gtest-string.cc.
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
+ const String &test_name) {
+ const String& full_name = String::Format("%s.%s",
+ test_case_name.c_str(),
+ test_name.c_str());
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ String positive;
+ String negative;
+ if (dash == NULL) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = String("");
+ } else {
+ positive.Set(p, dash - p); // Everything up to the dash
+ negative = String(dash+1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#ifdef GTEST_OS_WINDOWS
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+ // Google Test should handle an exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception.
+ return (GTEST_FLAG(catch_exceptions) &&
+ exception_code != EXCEPTION_BREAKPOINT) ?
+ EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_OS_WINDOWS
+
+} // namespace internal
+
+// The interface for printing the result of a UnitTest
+class UnitTestEventListenerInterface {
+ public:
+ // The d'tor is pure virtual as this is an abstract class.
+ virtual ~UnitTestEventListenerInterface() = 0;
+
+ // Called before the unit test starts.
+ virtual void OnUnitTestStart(const UnitTest*) {}
+
+ // Called after the unit test ends.
+ virtual void OnUnitTestEnd(const UnitTest*) {}
+
+ // Called before the test case starts.
+ virtual void OnTestCaseStart(const TestCase*) {}
+
+ // Called after the test case ends.
+ virtual void OnTestCaseEnd(const TestCase*) {}
+
+ // Called before the global set-up starts.
+ virtual void OnGlobalSetUpStart(const UnitTest*) {}
+
+ // Called after the global set-up ends.
+ virtual void OnGlobalSetUpEnd(const UnitTest*) {}
+
+ // Called before the global tear-down starts.
+ virtual void OnGlobalTearDownStart(const UnitTest*) {}
+
+ // Called after the global tear-down ends.
+ virtual void OnGlobalTearDownEnd(const UnitTest*) {}
+
+ // Called before the test starts.
+ virtual void OnTestStart(const TestInfo*) {}
+
+ // Called after the test ends.
+ virtual void OnTestEnd(const TestInfo*) {}
+
+ // Called after an assertion.
+ virtual void OnNewTestPartResult(const TestPartResult*) {}
+};
+
+// Constructs an empty TestPartResultArray.
+TestPartResultArray::TestPartResultArray()
+ : list_(new internal::List<TestPartResult>) {
+}
+
+// Destructs a TestPartResultArray.
+TestPartResultArray::~TestPartResultArray() {
+ delete list_;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+ list_->PushBack(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ abort();
+ }
+
+ const internal::ListNode<TestPartResult>* p = list_->Head();
+ for (int i = 0; i < index; i++) {
+ p = p->next();
+ }
+
+ return p->element();
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return list_->size();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : old_reporter_(UnitTest::GetInstance()->impl()->
+ test_part_result_reporter()),
+ result_(result) {
+ internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();
+ impl->set_test_part_result_reporter(this);
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+ UnitTest::GetInstance()->impl()->
+ set_test_part_result_reporter(old_reporter_);
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ result_->Append(result);
+}
+
+namespace internal {
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResultType type,
+ const char* substr) {
+ const String expected(
+ type == TPRT_FATAL_FAILURE ? "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure(msg);
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ if (strstr(r.message(), substr) == NULL) {
+ msg << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+ const TestPartResultArray* results,
+ TestPartResultType type,
+ const char* substr)
+ : results_(results),
+ type_(type),
+ substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());
+}
+
+// Reports a test part result.
+void UnitTestImpl::ReportTestPartResult(const TestPartResult& result) {
+ current_test_result()->AddTestPartResult(result);
+ result_printer()->OnNewTestPartResult(&result);
+}
+
+// Returns the current test part result reporter.
+TestPartResultReporterInterface* UnitTestImpl::test_part_result_reporter() {
+ return test_part_result_reporter_;
+}
+
+// Sets the current test part result reporter.
+void UnitTestImpl::set_test_part_result_reporter(
+ TestPartResultReporterInterface* reporter) {
+ test_part_result_reporter_ = reporter;
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+ return test_cases_.CountIf(TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+ return test_cases_.CountIf(TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+ return test_cases_.size();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+ return test_cases_.CountIf(ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ (void)skip_count;
+ return String("");
+}
+
+static TimeInMillis GetTimeInMillis() {
+#ifdef _WIN32_WCE // We are on Windows CE
+ // Difference between 1970-01-01 and 1601-01-01 in miliseconds.
+ // http://analogous.blogspot.com/2005/04/epoch.html
+ const TimeInMillis kJavaEpochToWinFileTimeDelta = 11644473600000UL;
+ const DWORD kTenthMicrosInMilliSecond = 10000;
+
+ SYSTEMTIME now_systime;
+ FILETIME now_filetime;
+ ULARGE_INTEGER now_int64;
+ // TODO(kenton): Shouldn't this just use GetSystemTimeAsFileTime()?
+ GetSystemTime(&now_systime);
+ if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+ now_int64.LowPart = now_filetime.dwLowDateTime;
+ now_int64.HighPart = now_filetime.dwHighDateTime;
+ now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+ kJavaEpochToWinFileTimeDelta;
+ return now_int64.QuadPart;
+ }
+ return 0;
+#elif defined(_WIN32) && !defined(HAS_GETTIMEOFDAY)
+ __timeb64 now;
+#ifdef _MSC_VER
+ // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+ // (deprecated function) there.
+ // TODO(kenton): Use GetTickCount()? Or use SystemTimeToFileTime()
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ _ftime64(&now);
+#pragma warning(pop) // Restores the warning state.
+#else
+ _ftime64(&now);
+#endif // _MSC_VER
+ return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif defined(HAS_GETTIMEOFDAY)
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+#error "Don't know how to get the current time on your system."
+ return 0;
+#endif
+}
+
+// Utilities
+
+// class String
+
+// Returns the input enclosed in double quotes if it's not NULL;
+// otherwise returns "(null)". For example, "\"Hello\"" is returned
+// for input "Hello".
+//
+// This is useful for printing a C string in the syntax of a literal.
+//
+// Known issue: escape sequences are not handled yet.
+String String::ShowCStringQuoted(const char* c_str) {
+ return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
+}
+
+// Copies at most length characters from str into a newly-allocated
+// piece of memory of size length+1. The memory is allocated with new[].
+// A terminating null byte is written to the memory, and a pointer to it
+// is returned. If str is NULL, NULL is returned.
+static char* CloneString(const char* str, size_t length) {
+ if (str == NULL) {
+ return NULL;
+ } else {
+ char* const clone = new char[length + 1];
+ // MSVC 8 deprecates strncpy(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ strncpy(clone, str, length);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ strncpy(clone, str, length);
+#endif // GTEST_OS_WINDOWS
+ clone[length] = '\0';
+ return clone;
+ }
+}
+
+// Clones a 0-terminated C string, allocating memory using new. The
+// caller is responsible for deleting[] the return value. Returns the
+// cloned string, or NULL if the input is NULL.
+const char * String::CloneCString(const char* c_str) {
+ return (c_str == NULL) ?
+ NULL : CloneString(c_str, strlen(c_str));
+}
+
+// Compares two C strings. Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len,
+ Message* msg) {
+ for (size_t i = 0; i != len; i++) {
+ // TODO(wan): consider allowing a testing::String object to
+ // contain '\0'. This will make it behave more like std::string,
+ // and will allow ToUtf8String() to return the correct encoding
+ // for '\0' s.t. we can get rid of the conditional here (and in
+ // several other places).
+ if (wstr[i]) {
+ *msg << internal::ToUtf8String(wstr[i]);
+ } else {
+ *msg << '\0';
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+} // namespace internal
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+namespace internal {
+
+// Formats a value to be used in a failure message.
+
+// For a char value, we print it as a C++ char literal and as an
+// unsigned integer (both in decimal and in hexadecimal).
+String FormatForFailureMessage(char ch) {
+ const unsigned int ch_as_uint = ch;
+ // A String object cannot contain '\0', so we print "\\0" when ch is
+ // '\0'.
+ return String::Format("'%s' (%u, 0x%X)",
+ ch ? String::Format("%c", ch).c_str() : "\\0",
+ ch_as_uint, ch_as_uint);
+}
+
+// For a wchar_t value, we print it as a C++ wchar_t literal and as an
+// unsigned integer (both in decimal and in hexidecimal).
+String FormatForFailureMessage(wchar_t wchar) {
+ // The C++ standard doesn't specify the exact size of the wchar_t
+ // type. It just says that it shall have the same size as another
+ // integral type, called its underlying type.
+ //
+ // Therefore, in order to print a wchar_t value in the numeric form,
+ // we first convert it to the largest integral type (UInt64) and
+ // then print the converted value.
+ //
+ // We use streaming to print the value as "%llu" doesn't work
+ // correctly with MSVC 7.1.
+ const UInt64 wchar_as_uint64 = wchar;
+ Message msg;
+ // A String object cannot contain '\0', so we print "\\0" when wchar is
+ // L'\0'.
+ msg << "L'" << (wchar ? ToUtf8String(wchar).c_str() : "\\0") << "' ("
+ << wchar_as_uint64 << ", 0x" << ::std::setbase(16)
+ << wchar_as_uint64 << ")";
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// AssertionResult constructor.
+AssertionResult::AssertionResult(const internal::String& failure_message)
+ : failure_message_(failure_message) {
+}
+
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+ return AssertionResult();
+}
+
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& message) {
+ return AssertionResult(message.GetString());
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case) {
+ Message msg;
+ msg << "Value of: " << actual_expression;
+ if (actual_value != actual_expression) {
+ msg << "\n Actual: " << actual_value;
+ }
+
+ msg << "\nExpected: " << expected_expression;
+ if (ignoring_case) {
+ msg << " (ignoring case)";
+ }
+ if (expected_value != expected_expression) {
+ msg << "\nWhich is: " << expected_value;
+ }
+
+ return AssertionFailure(msg);
+}
+
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error) {
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // TODO(wan): do not print the value of an expression if it's
+ // already a literal.
+ Message msg;
+ msg << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+ return AssertionFailure(msg);
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2) {
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ StrStream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ StrStream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ Message msg;
+ msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StrStreamToString(&val1_ss) << " vs "
+ << StrStreamToString(&val2_ss);
+
+ return AssertionFailure(msg);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2) {
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2) {
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+} // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack. NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack) {
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack) {
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure(
+ Message()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"");
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#ifdef GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) { // NOLINT
+#ifdef _WIN32_WCE
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+#else
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096; // String::Format can't exceed this length.
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ hr, // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ NULL); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
+ for (; message_length && isspace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+#endif // _WIN32_WCE
+
+ const String error_hex(String::Format("0x%08X ", hr));
+ Message msg;
+ msg << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << error_text << "\n";
+
+ return ::testing::AssertionFailure(msg);
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+ const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code-point to its UTF-8 encoding.
+String ToUtf8String(wchar_t wchar) {
+ char str[5] = {}; // Initializes str to all '\0' characters.
+
+ UInt32 code = static_cast<UInt32>(wchar);
+ if (code <= kMaxCodePoint1) {
+ str[0] = static_cast<char>(code); // 0xxxxxxx
+ } else if (code <= kMaxCodePoint2) {
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code); // 110xxxxx
+ } else if (code <= kMaxCodePoint3) {
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code); // 1110xxxx
+ } else if (code <= kMaxCodePoint4) {
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code); // 11110xxx
+ } else {
+ return String::Format("(Invalid Unicode 0x%llX)",
+ static_cast<UInt64>(wchar));
+ }
+
+ return String(str);
+}
+
+// Converts a wide C string to a String using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+String String::ShowWideCString(const wchar_t * wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ StrStream ss;
+ while (*wide_c_str) {
+ ss << internal::ToUtf8String(*wide_c_str++);
+ }
+
+ return internal::StrStreamToString(&ss);
+}
+
+// Similar to ShowWideCString(), except that this function encloses
+// the converted string in double quotes.
+String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String::Format("L\"%s\"",
+ String::ShowWideCString(wide_c_str).c_str());
+}
+
+// Compares two wide C strings. Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual) {
+ if (String::WideCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowWideCStringQuoted(expected),
+ String::ShowWideCStringQuoted(actual),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2) {
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << String::ShowWideCStringQuoted(s1)
+ << " vs " << String::ShowWideCStringQuoted(s2);
+ return AssertionFailure(msg);
+}
+
+// Compares two C strings, ignoring case. Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+#ifdef GTEST_OS_WINDOWS
+ return _stricmp(lhs, rhs) == 0;
+#else // GTEST_OS_WINDOWS
+ return strcasecmp(lhs, rhs) == 0;
+#endif // GTEST_OS_WINDOWS
+}
+
+// Constructs a String by copying a given number of chars from a
+// buffer. E.g. String("hello", 3) will create the string "hel".
+String::String(const char * buffer, size_t len) {
+ char * const temp = new char[ len + 1 ];
+ memcpy(temp, buffer, len);
+ temp[ len ] = '\0';
+ c_str_ = temp;
+}
+
+// Compares this with another String.
+// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+// if this is greater than rhs.
+int String::Compare(const String & rhs) const {
+ if ( c_str_ == NULL ) {
+ return rhs.c_str_ == NULL ? 0 : -1; // NULL < anything except NULL
+ }
+
+ return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_);
+}
+
+// Returns true iff this String ends with the given suffix. *Any*
+// String is considered to end with a NULL or empty suffix.
+bool String::EndsWith(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str_ == NULL) return false;
+
+ const size_t this_len = strlen(c_str_);
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Returns true iff this String ends with the given suffix, ignoring case.
+// Any String is considered to end with a NULL or empty suffix.
+bool String::EndsWithCaseInsensitive(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str_ == NULL) return false;
+
+ const size_t this_len = strlen(c_str_);
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Sets the 0-terminated C string this String object represents. The
+// old string in this object is deleted, and this object will own a
+// clone of the input string. This function copies only up to length
+// bytes (plus a terminating null byte), or until the first null byte,
+// whichever comes first.
+//
+// This function works even when the c_str parameter has the same
+// value as that of the c_str_ field.
+void String::Set(const char * c_str, size_t length) {
+ // Makes sure this works when c_str == c_str_
+ const char* const temp = CloneString(c_str, length);
+ delete[] c_str_;
+ c_str_ = temp;
+}
+
+// Assigns a C string to this object. Self-assignment works.
+const String& String::operator=(const char* c_str) {
+ // Makes sure this works when c_str == c_str_
+ if (c_str != c_str_) {
+ delete[] c_str_;
+ c_str_ = CloneCString(c_str);
+ }
+ return *this;
+}
+
+// Formats a list of arguments to a String, using the same format
+// spec string as for printf.
+//
+// We do not use the StringPrintf class as it is not universally
+// available.
+//
+// The result is limited to 4096 characters (including the tailing 0).
+// If 4096 characters are not enough to format the input,
+// "<buffer exceeded>" is returned.
+String String::Format(const char * format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ char buffer[4096];
+ // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ const int size =
+ vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ const int size =
+ vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#endif // GTEST_OS_WINDOWS
+ va_end(args);
+
+ return String(size >= 0 ? buffer : "<buffer exceeded>");
+}
+
+// Converts the buffer in a StrStream to a String, converting NUL
+// bytes to "\\0" along the way.
+String StrStreamToString(StrStream* ss) {
+#if GTEST_HAS_STD_STRING
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+#else
+ const char* const start = ss->str();
+ const char* const end = start + ss->pcount();
+#endif // GTEST_HAS_STD_STRING
+
+ // We need to use a helper StrStream to do this transformation
+ // because String doesn't support push_back().
+ StrStream helper;
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ helper << "\\0"; // Replaces NUL with "\\0";
+ } else {
+ helper.put(*ch);
+ }
+ }
+
+#if GTEST_HAS_STD_STRING
+ return String(helper.str().c_str());
+#else
+ const String str(helper.str(), helper.pcount());
+ helper.freeze(false);
+ ss->freeze(false);
+ return str;
+#endif // GTEST_HAS_STD_STRING
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const String user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+
+ Message msg;
+ msg << gtest_msg << "\n" << user_msg_string;
+
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os << result.file_name() << ":"
+ << result.line_number() << ": "
+ << (result.type() == TPRT_SUCCESS ? "Success" :
+ result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" :
+ "Non-fatal failure") << ":\n"
+ << result.message() << std::endl;
+}
+
+namespace internal {
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0),
+ elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+ test_part_results_.PushBack(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const TestProperty& test_property) {
+ if (!ValidateTestProperty(test_property)) {
+ return;
+ }
+ MutexLock lock(&test_properites_mutex_);
+ ListNode<TestProperty>* const node_with_matching_key =
+ test_properties_.FindIf(TestPropertyKeyIs(test_property.key()));
+ if (node_with_matching_key == NULL) {
+ test_properties_.PushBack(test_property);
+ return;
+ }
+ TestProperty& property_with_matching_key = node_with_matching_key->element();
+ property_with_matching_key.SetValue(test_property.value());
+}
+
+// Adds a failure if the key is a reserved attribute of Google Test testcase tags.
+// Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
+ String key(test_property.key());
+ if (key == "name" || key == "status" || key == "time" || key == "classname") {
+ ADD_FAILURE()
+ << "Reserved key used in RecordProperty(): "
+ << key
+ << " ('name', 'status', 'time', and 'classname' are reserved by "
+ << GTEST_NAME << ")";
+ return false;
+ }
+ return true;
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.Clear();
+ test_properties_.Clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true iff the test part passed.
+static bool TestPartPassed(const TestPartResult & result) {
+ return result.passed();
+}
+
+// Gets the number of successful test parts.
+int TestResult::successful_part_count() const {
+ return test_part_results_.CountIf(TestPartPassed);
+}
+
+// Returns true iff the test part failed.
+static bool TestPartFailed(const TestPartResult & result) {
+ return result.failed();
+}
+
+// Gets the number of failed test parts.
+int TestResult::failed_part_count() const {
+ return test_part_results_.CountIf(TestPartFailed);
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult & result) {
+ return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return test_part_results_.CountIf(TestPartFatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+ return test_part_results_.size();
+}
+
+} // namespace internal
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+ : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+ delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, const char* value) {
+ UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, int value) {
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+#ifdef GTEST_OS_WINDOWS
+// We are on Windows.
+
+// Adds an "exception thrown" fatal failure to the current test.
+static void AddExceptionThrownFailure(DWORD exception_code,
+ const char* location) {
+ Message message;
+ message << "Exception thrown with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " in " << location << ".";
+
+ UnitTest* const unit_test = UnitTest::GetInstance();
+ unit_test->AddTestPartResult(
+ TPRT_FATAL_FAILURE,
+ static_cast<const char *>(NULL),
+ // We have no info about the source file where the exception
+ // occurred.
+ -1, // We have no info on which line caused the exception.
+ message.GetString(),
+ internal::String(""));
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test case. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestCase* const test_case = impl->current_test_case();
+
+ // Info about the first test in the current test case.
+ const internal::TestInfoImpl* const first_test_info =
+ test_case->test_info_list().Head()->element()->impl();
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const internal::TestInfoImpl* const this_test_info =
+ impl->current_test_info()->impl();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTypeId<Test>();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTypeId<Test>();
+
+ if (first_is_TEST || this_is_TEST) {
+ // The user mixed TEST and TEST_F in this test case - we'll tell
+ // him/her how to fix it.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test case is\n"
+ << "illegal. In test case " << this_test_info->test_case_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // The user defined two fixture classes with the same name in
+ // two namespaces - we'll tell him/her how to fix it.
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case "
+ << this_test_info->test_case_name() << ",\n"
+ << "you defined test " << first_test_name
+ << " and test " << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test cases.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// Runs the test and updates the test result.
+void Test::Run() {
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+#ifdef GTEST_OS_WINDOWS
+ // We are on Windows.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ SetUp();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
+ }
+
+ // We will run the test only if SetUp() had no fatal failure.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TestBody();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "the test body");
+ }
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TearDown();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
+ }
+
+#else // We are on Linux or Mac - exceptions are disabled.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ SetUp();
+
+ // We will run the test only if SetUp() was successful.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TestBody();
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TearDown();
+#endif // GTEST_OS_WINDOWS
+}
+
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object.
+TestInfo::TestInfo(const char* test_case_name,
+ const char* name,
+ internal::TypeId fixture_class_id,
+ TestMaker maker) {
+ impl_ = new internal::TestInfoImpl(this, test_case_name, name,
+ fixture_class_id, maker);
+}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() {
+ delete impl_;
+}
+
+// Creates a TestInfo object and registers it with the UnitTest
+// singleton; returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// maker: pointer to the function that creates a test object
+TestInfo* TestInfo::MakeAndRegisterInstance(
+ const char* test_case_name,
+ const char* name,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestMaker maker) {
+ TestInfo* const test_info =
+ new TestInfo(test_case_name, name, fixture_class_id, maker);
+ internal::GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+// Returns the test case name.
+const char* TestInfo::test_case_name() const {
+ return impl_->test_case_name();
+}
+
+// Returns the test name.
+const char* TestInfo::name() const {
+ return impl_->name();
+}
+
+// Returns true if this test should run.
+bool TestInfo::should_run() const { return impl_->should_run(); }
+
+// Returns the result of the test.
+const internal::TestResult* TestInfo::result() const { return impl_->result(); }
+
+// Increments the number of death tests encountered in this test so
+// far.
+int TestInfo::increment_death_test_count() {
+ return impl_->result()->increment_death_test_count();
+}
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true iff the test name of test_info matches name_.
+ bool operator()(const TestInfo * test_info) const {
+ return test_info && internal::String(test_info->name()).Compare(name_) == 0;
+ }
+
+ private:
+ internal::String name_;
+};
+
+} // namespace
+
+// Finds and returns a TestInfo with the given name. If one doesn't
+// exist, returns NULL.
+TestInfo * TestCase::GetTestInfo(const char* test_name) {
+ // Can we find a TestInfo with the given name?
+ internal::ListNode<TestInfo *> * const node = test_info_list_->FindIf(
+ TestNameIs(test_name));
+
+ // Returns the TestInfo found.
+ return node ? node->element() : NULL;
+}
+
+namespace internal {
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfoImpl::Run() {
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(parent_);
+
+ // Notifies the unit test event listener that a test is about to
+ // start.
+ UnitTestEventListenerInterface* const result_printer =
+ impl->result_printer();
+ result_printer->OnTestStart(parent_);
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+#ifdef GTEST_OS_WINDOWS
+ // We are on Windows.
+ Test* test = NULL;
+
+ __try {
+ // Creates the test object.
+ test = (*maker_)();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(),
+ "the test fixture's constructor");
+ return;
+ }
+#else // We are on Linux or Mac OS - exceptions are disabled.
+
+ // TODO(wan): If test->Run() throws, test won't be deleted. This is
+ // not a problem now as we don't use exceptions. If we were to
+ // enable exceptions, we should revise the following to be
+ // exception-safe.
+
+ // Creates the test object.
+ Test* test = (*maker_)();
+#endif // GTEST_OS_WINDOWS
+
+ // Runs the test only if the constructor of the test fixture didn't
+ // generate a fatal failure.
+ if (!Test::HasFatalFailure()) {
+ test->Run();
+ }
+
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ delete test;
+ test = NULL;
+
+ result_.set_elapsed_time(GetTimeInMillis() - start);
+
+ // Notifies the unit test event listener that a test has just finished.
+ result_printer->OnTestEnd(parent_);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(NULL);
+}
+
+} // namespace internal
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+ return test_info_list_->CountIf(TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+ return test_info_list_->CountIf(TestFailed);
+}
+
+int TestCase::disabled_test_count() const {
+ return test_info_list_->CountIf(TestDisabled);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+ return test_info_list_->CountIf(ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+ return test_info_list_->size();
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+// name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* name,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+ : name_(name),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ elapsed_time_(0) {
+ test_info_list_ = new internal::List<TestInfo *>;
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+ // Deletes every Test in the collection.
+ test_info_list_->ForEach(internal::Delete<TestInfo>);
+
+ // Then deletes the Test collection.
+ delete test_info_list_;
+ test_info_list_ = NULL;
+}
+
+// Adds a test to this test case. Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+ test_info_list_->PushBack(test_info);
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_case(this);
+
+ UnitTestEventListenerInterface * const result_printer =
+ impl->result_printer();
+
+ result_printer->OnTestCaseStart(this);
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ set_up_tc_();
+
+ const internal::TimeInMillis start = internal::GetTimeInMillis();
+ test_info_list_->ForEach(internal::TestInfoImpl::RunTest);
+ elapsed_time_ = internal::GetTimeInMillis() - start;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ tear_down_tc_();
+ result_printer->OnTestCaseEnd(this);
+ impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+ test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult);
+}
+
+
+// class UnitTestEventListenerInterface
+
+// The virtual d'tor.
+UnitTestEventListenerInterface::~UnitTestEventListenerInterface() {
+}
+
+// A result printer that never prints anything. Used in the child process
+// of an exec-style death test to avoid needless output clutter.
+class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {};
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static internal::String FormatCountableNoun(int count,
+ const char * singular_form,
+ const char * plural_form) {
+ return internal::String::Format("%d %s", count,
+ count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static internal::String FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static internal::String FormatTestCaseCount(int test_case_count) {
+ return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResultType enum to human-friendly string
+// representation. Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE
+// are translated to "Failure", as the user usually doesn't care about
+// the difference between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResultType type) {
+ switch (type) {
+ case TPRT_SUCCESS:
+ return "Success";
+
+ case TPRT_NONFATAL_FAILURE:
+ case TPRT_FATAL_FAILURE:
+ return "Failure";
+ }
+
+ return "Unknown result type";
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(
+ const TestPartResult & test_part_result) {
+ const char * const file_name = test_part_result.file_name();
+
+ printf("%s", file_name == NULL ? "unknown file" : file_name);
+ if (test_part_result.line_number() >= 0) {
+ printf(":%d", test_part_result.line_number());
+ }
+ printf(": %s\n", TestPartResultTypeToString(test_part_result.type()));
+ printf("%s\n", test_part_result.message());
+ fflush(stdout);
+}
+
+// class PrettyUnitTestResultPrinter
+
+namespace internal {
+
+enum GTestColor {
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+#ifdef _WIN32
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ }
+ return 0;
+}
+
+#else
+
+// Returns the ANSI color code for the given color.
+const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ };
+ return NULL;
+}
+
+#endif // _WIN32
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#ifdef _WIN32
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // _WIN32
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0);
+ // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#ifdef _WIN32
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ SetConsoleTextAttribute(stdout_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ vprintf(fmt, args);
+
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // _WIN32
+ va_end(args);
+}
+
+} // namespace internal
+
+using internal::ColoredPrintf;
+using internal::COLOR_RED;
+using internal::COLOR_GREEN;
+using internal::COLOR_YELLOW;
+
+// This class implements the UnitTestEventListenerInterface interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char * test_case, const char * test) {
+ printf("%s.%s", test_case, test);
+ }
+
+ // The following methods override what's in the
+ // UnitTestEventListenerInterface class.
+ virtual void OnUnitTestStart(const UnitTest * unit_test);
+ virtual void OnGlobalSetUpStart(const UnitTest*);
+ virtual void OnTestCaseStart(const TestCase * test_case);
+ virtual void OnTestStart(const TestInfo * test_info);
+ virtual void OnNewTestPartResult(const TestPartResult * result);
+ virtual void OnTestEnd(const TestInfo * test_info);
+ virtual void OnGlobalTearDownStart(const UnitTest*);
+ virtual void OnUnitTestEnd(const UnitTest * unit_test);
+
+ private:
+ internal::String test_case_name_;
+};
+
+// Called before the unit test starts.
+void PrettyUnitTestResultPrinter::OnUnitTestStart(
+ const UnitTest * unit_test) {
+ const char * const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: %s filter = %s\n", GTEST_NAME, filter);
+ }
+
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(impl->test_to_run_count()).c_str(),
+ FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(
+ const TestCase * test_case) {
+ test_case_name_ = test_case->name();
+ const internal::String counts =
+ FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s\n", counts.c_str(), test_case_name_.c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) {
+ ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
+ PrintTestName(test_case_name_.c_str(), test_info->name());
+ printf("\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) {
+ if (test_info->result()->Passed()) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ }
+ PrintTestName(test_case_name_.c_str(), test_info->name());
+ printf("\n");
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnNewTestPartResult(
+ const TestPartResult * result) {
+ // If the test part succeeded, we don't need to do anything.
+ if (result->type() == TPRT_SUCCESS)
+ return;
+
+ // Print failure message from the assertion (e.g. expected this and got that).
+ PrintTestPartResult(*result);
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+namespace internal {
+
+// Internal helper for printing the list of failed tests.
+static void PrintFailedTestsPretty(const UnitTestImpl* impl) {
+ const int failed_test_count = impl->failed_test_count();
+ if (failed_test_count == 0) {
+ return;
+ }
+
+ for (const internal::ListNode<TestCase*>* node = impl->test_cases()->Head();
+ node != NULL; node = node->next()) {
+ const TestCase* const tc = node->element();
+ if (!tc->should_run() || (tc->failed_test_count() == 0)) {
+ continue;
+ }
+ for (const internal::ListNode<TestInfo*>* tinode =
+ tc->test_info_list().Head();
+ tinode != NULL; tinode = tinode->next()) {
+ const TestInfo* const ti = tinode->element();
+ if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) {
+ continue;
+ }
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s.%s\n", ti->test_case_name(), ti->name());
+ }
+ }
+}
+
+} // namespace internal
+
+void PrettyUnitTestResultPrinter::OnUnitTestEnd(
+ const UnitTest * unit_test) {
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("%s from %s ran.\n",
+ FormatTestCount(impl->test_to_run_count()).c_str(),
+ FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+ ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str());
+
+ int num_failures = impl->failed_test_count();
+ if (!impl->Passed()) {
+ const int failed_test_count = impl->failed_test_count();
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+ internal::PrintFailedTestsPretty(impl);
+ printf("\n%2d FAILED %s\n", num_failures,
+ num_failures == 1 ? "TEST" : "TESTS");
+ }
+
+ int num_disabled = impl->disabled_test_count();
+ if (num_disabled) {
+ if (!num_failures) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(COLOR_YELLOW,
+ " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled,
+ num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class UnitTestEventsRepeater
+//
+// This class forwards events to other event listeners.
+class UnitTestEventsRepeater : public UnitTestEventListenerInterface {
+ public:
+ typedef internal::List<UnitTestEventListenerInterface *> Listeners;
+ typedef internal::ListNode<UnitTestEventListenerInterface *> ListenersNode;
+ UnitTestEventsRepeater() {}
+ virtual ~UnitTestEventsRepeater();
+ void AddListener(UnitTestEventListenerInterface *listener);
+
+ virtual void OnUnitTestStart(const UnitTest* unit_test);
+ virtual void OnUnitTestEnd(const UnitTest* unit_test);
+ virtual void OnGlobalSetUpStart(const UnitTest* unit_test);
+ virtual void OnGlobalSetUpEnd(const UnitTest* unit_test);
+ virtual void OnGlobalTearDownStart(const UnitTest* unit_test);
+ virtual void OnGlobalTearDownEnd(const UnitTest* unit_test);
+ virtual void OnTestCaseStart(const TestCase* test_case);
+ virtual void OnTestCaseEnd(const TestCase* test_case);
+ virtual void OnTestStart(const TestInfo* test_info);
+ virtual void OnTestEnd(const TestInfo* test_info);
+ virtual void OnNewTestPartResult(const TestPartResult* result);
+
+ private:
+ Listeners listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTestEventsRepeater);
+};
+
+UnitTestEventsRepeater::~UnitTestEventsRepeater() {
+ for (ListenersNode* listener = listeners_.Head();
+ listener != NULL;
+ listener = listener->next()) {
+ delete listener->element();
+ }
+}
+
+void UnitTestEventsRepeater::AddListener(
+ UnitTestEventListenerInterface *listener) {
+ listeners_.PushBack(listener);
+}
+
+// Since the methods are identical, use a macro to reduce boilerplate.
+// This defines a member that repeats the call to all listeners.
+#define GTEST_REPEATER_METHOD(Name, Type) \
+void UnitTestEventsRepeater::Name(const Type* parameter) { \
+ for (ListenersNode* listener = listeners_.Head(); \
+ listener != NULL; \
+ listener = listener->next()) { \
+ listener->element()->Name(parameter); \
+ } \
+}
+
+GTEST_REPEATER_METHOD(OnUnitTestStart, UnitTest)
+GTEST_REPEATER_METHOD(OnUnitTestEnd, UnitTest)
+GTEST_REPEATER_METHOD(OnGlobalSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD(OnGlobalSetUpEnd, UnitTest)
+GTEST_REPEATER_METHOD(OnGlobalTearDownStart, UnitTest)
+GTEST_REPEATER_METHOD(OnGlobalTearDownEnd, UnitTest)
+GTEST_REPEATER_METHOD(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD(OnTestCaseEnd, TestCase)
+GTEST_REPEATER_METHOD(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD(OnTestEnd, TestInfo)
+GTEST_REPEATER_METHOD(OnNewTestPartResult, TestPartResult)
+
+#undef GTEST_REPEATER_METHOD
+
+// End PrettyUnitTestResultPrinter
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ virtual void OnUnitTestEnd(const UnitTest* unit_test);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static internal::String EscapeXml(const char* str,
+ bool is_attribute);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static internal::String EscapeXmlAttribute(const char* str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static internal::String EscapeXmlText(const char* str) {
+ return EscapeXml(str, false);
+ }
+
+ // Prints an XML representation of a TestInfo object.
+ static void PrintXmlTestInfo(FILE* out,
+ const char* test_case_name,
+ const TestInfo* test_info);
+
+ // Prints an XML representation of a TestCase object
+ static void PrintXmlTestCase(FILE* out, const TestCase* test_case);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the String is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static internal::String TestPropertiesAsXmlAttributes(
+ const internal::TestResult* result);
+
+ // The output file.
+ const internal::String output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.c_str() == NULL || output_file_.empty()) {
+ fprintf(stderr, "XML output file may not be null\n");
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) {
+ FILE* xmlout = NULL;
+ internal::FilePath output_file(output_file_);
+ internal::FilePath output_dir(output_file.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ // MSVC 8 deprecates fopen(), so we want to suppress warning 4996
+ // (deprecated function) there.
+#ifdef GTEST_OS_WINDOWS
+ // We are on Windows.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ xmlout = fopen(output_file_.c_str(), "w");
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ xmlout = fopen(output_file_.c_str(), "w");
+#endif // GTEST_OS_WINDOWS
+ }
+ if (xmlout == NULL) {
+ // TODO(wan): report the reason of the failure.
+ //
+ // We don't do it for now as:
+ //
+ // 1. There is no urgent need for it.
+ // 2. It's a bit involved to make the errno variable thread-safe on
+ // all three operating systems (Linux, Windows, and Mac OS).
+ // 3. To interpret the meaning of errno in a thread-safe way,
+ // we need the strerror_r() function, which is not available on
+ // Windows.
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ output_file_.c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ PrintXmlUnitTest(xmlout, unit_test);
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,
+ bool is_attribute) {
+ Message m;
+
+ if (str != NULL) {
+ for (const char* src = str; *src; ++src) {
+ switch (*src) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(*src)) {
+ if (is_attribute && IsNormalizableWhitespace(*src))
+ m << internal::String::Format("&#x%02X;", unsigned(*src));
+ else
+ m << *src;
+ }
+ break;
+ }
+ }
+ }
+
+ return m.GetString();
+}
+
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuite name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="..." />
+// <failure message="..." /> <-- individual assertion failures
+// <failure message="..." />
+// </testcase>
+// </testsuite>
+// </testsuite>
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
+ const char* test_case_name,
+ const TestInfo* test_info) {
+ const internal::TestResult * const result = test_info->result();
+ const internal::List<TestPartResult> &results = result->test_part_results();
+ fprintf(out,
+ " <testcase name=\"%s\" status=\"%s\" time=\"%s\" "
+ "classname=\"%s\"%s",
+ EscapeXmlAttribute(test_info->name()).c_str(),
+ test_info->should_run() ? "run" : "notrun",
+ internal::StreamableToString(result->elapsed_time()).c_str(),
+ EscapeXmlAttribute(test_case_name).c_str(),
+ TestPropertiesAsXmlAttributes(result).c_str());
+
+ int failures = 0;
+ for (const internal::ListNode<TestPartResult>* part_node = results.Head();
+ part_node != NULL;
+ part_node = part_node->next()) {
+ const TestPartResult& part = part_node->element();
+ if (part.failed()) {
+ const internal::String message =
+ internal::String::Format("%s:%d\n%s", part.file_name(),
+ part.line_number(), part.message());
+ if (++failures == 1)
+ fprintf(out, ">\n");
+ fprintf(out,
+ " <failure message=\"%s\" type=\"\"/>\n",
+ EscapeXmlAttribute(message.c_str()).c_str());
+ }
+ }
+
+ if (failures == 0)
+ fprintf(out, " />\n");
+ else
+ fprintf(out, " </testcase>\n");
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+ const TestCase* test_case) {
+ fprintf(out,
+ " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
+ "disabled=\"%d\" ",
+ EscapeXmlAttribute(test_case->name()).c_str(),
+ test_case->total_test_count(),
+ test_case->failed_test_count(),
+ test_case->disabled_test_count());
+ fprintf(out,
+ "errors=\"0\" time=\"%s\">\n",
+ internal::StreamableToString(test_case->elapsed_time()).c_str());
+ for (const internal::ListNode<TestInfo*>* info_node =
+ test_case->test_info_list().Head();
+ info_node != NULL;
+ info_node = info_node->next()) {
+ PrintXmlTestInfo(out, test_case->name(), info_node->element());
+ }
+ fprintf(out, " </testsuite>\n");
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+ const UnitTest* unit_test) {
+ const internal::UnitTestImpl* const impl = unit_test->impl();
+ fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(out,
+ "<testsuite tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
+ "errors=\"0\" time=\"%s\" ",
+ impl->total_test_count(),
+ impl->failed_test_count(),
+ impl->disabled_test_count(),
+ internal::StreamableToString(impl->elapsed_time()).c_str());
+ fprintf(out, "name=\"AllTests\">\n");
+ for (const internal::ListNode<TestCase*>* case_node =
+ impl->test_cases()->Head();
+ case_node != NULL;
+ case_node = case_node->next()) {
+ PrintXmlTestCase(out, case_node->element());
+ }
+ fprintf(out, "</testsuite>\n");
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const internal::TestResult* result) {
+ using internal::TestProperty;
+ Message attributes;
+ const internal::List<TestProperty>& properties = result->test_properties();
+ for (const internal::ListNode<TestProperty>* property_node =
+ properties.Head();
+ property_node != NULL;
+ property_node = property_node->next()) {
+ const TestProperty& property = property_node->element();
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+namespace internal {
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+// L < UnitTest::mutex_
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
+ TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message = message.GetString();
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+// L < UnitTest::mutex_
+ScopedTrace::~ScopedTrace() {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as a String. Parameters:
+//
+// max_depth - the maximum number of stack frames to be included
+// in the trace.
+// skip_count - the number of top frames to be skipped; doesn't count
+// against max_depth.
+//
+// L < mutex_
+// We use "L < mutex_" to denote that the function may acquire mutex_.
+String OsStackTraceGetter::CurrentStackTrace(int, int) {
+ return String("");
+}
+
+// L < mutex_
+void OsStackTraceGetter::UponLeavingGTest() {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+ "... " GTEST_NAME " internal frames ...";
+
+} // namespace internal
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest * UnitTest::GetInstance() {
+ // When compiled with MSVC 7.1 in optimized mode, destroying the
+ // UnitTest object upon exiting the program messes up the exit code,
+ // causing successful tests to appear failed. We have to use a
+ // different implementation in this case to bypass the compiler bug.
+ // This implementation makes the compiler happy, at the cost of
+ // leaking the UnitTest object.
+#if _MSC_VER == 1310 && !defined(_DEBUG) // MSVC 7.1 and optimized build.
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // _MSC_VER==1310 && !defined(_DEBUG)
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+ if (env == NULL) {
+ return NULL;
+ }
+
+ impl_->environments()->PushBack(env);
+ impl_->environments_in_reverse_order()->PushFront(env);
+ return env;
+}
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+// L < mutex_
+void UnitTest::AddTestPartResult(TestPartResultType result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack()->size() > 0) {
+ msg << "\n" << GTEST_NAME << " trace:";
+
+ for (internal::ListNode<internal::TraceInfo>* node =
+ impl_->gtest_trace_stack()->Head();
+ node != NULL;
+ node = node->next()) {
+ const internal::TraceInfo& trace = node->element();
+ msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ msg << "\nStack trace:\n" << os_stack_trace;
+ }
+
+ const TestPartResult result =
+ TestPartResult(result_type, file_name, line_number,
+ msg.GetString().c_str());
+ impl_->test_part_result_reporter()->ReportTestPartResult(result);
+
+ // If this is a failure and the user wants the debugger to break on
+ // failures ...
+ if (result_type != TPRT_SUCCESS && GTEST_FLAG(break_on_failure)) {
+ // ... then we generate a seg fault.
+ *static_cast<int*>(NULL) = 1;
+ }
+}
+
+// Creates and adds a property to the current TestResult. If a property matching
+// the supplied value already exists, updates its value instead.
+void UnitTest::RecordPropertyForCurrentTest(const char* key,
+ const char* value) {
+ const internal::TestProperty test_property(key, value);
+ impl_->current_test_result()->RecordProperty(test_property);
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+#ifdef GTEST_OS_WINDOWS
+
+#if !defined(_WIN32_WCE)
+ // SetErrorMode doesn't exist on CE.
+ if (GTEST_FLAG(catch_exceptions)) {
+ // The user wants Google Test to catch exceptions thrown by the tests.
+
+ // This lets fatal errors be handled by us, instead of causing pop-ups.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+ }
+#endif // _WIN32_WCE
+
+ __try {
+ return impl_->RunAllTests();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
+ fflush(stdout);
+ return 1;
+ }
+
+#else
+ // We are on Linux or Mac OS. There is no exception of any kind.
+
+ return impl_->RunAllTests();
+#endif // GTEST_OS_WINDOWS
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestCase* UnitTest::current_test_case() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestInfo* UnitTest::current_test_info() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+// L < mutex_
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack()->PushFront(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+// L < mutex_
+void UnitTest::PopGTestTrace() {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack()->PopFront(NULL);
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+ test_cases_(),
+ last_death_test_case_(NULL),
+ current_test_case_(NULL),
+ current_test_info_(NULL),
+ ad_hoc_test_result_(),
+ result_printer_(NULL),
+ os_stack_trace_getter_(NULL),
+#ifdef GTEST_HAS_DEATH_TEST
+ elapsed_time_(0),
+ internal_run_death_test_flag_(NULL),
+ death_test_factory_(new DefaultDeathTestFactory) {
+#else
+ elapsed_time_(0) {
+#endif // GTEST_HAS_DEATH_TEST
+ // We do the assignment here instead of in the initializer list, as
+ // doing that latter causes MSVC to issue a warning about using
+ // 'this' in initializers.
+ test_part_result_reporter_ = this;
+}
+
+UnitTestImpl::~UnitTestImpl() {
+ // Deletes every TestCase.
+ test_cases_.ForEach(internal::Delete<TestCase>);
+
+ // Deletes every Environment.
+ environments_.ForEach(internal::Delete<Environment>);
+
+ // Deletes the current test result printer.
+ delete result_printer_;
+
+ delete os_stack_trace_getter_;
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+ // Constructor.
+ explicit TestCaseNameIs(const String& name)
+ : name_(name) {}
+
+ // Returns true iff the name of test_case matches name_.
+ bool operator()(const TestCase* test_case) const {
+ return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ String name_;
+};
+
+// Finds and returns a TestCase with the given name. If one doesn't
+// exist, creates one and returns it.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc) {
+ // Can we find a TestCase with the given name?
+ internal::ListNode<TestCase*>* node = test_cases_.FindIf(
+ TestCaseNameIs(test_case_name));
+
+ if (node == NULL) {
+ // No. Let's create one.
+ TestCase* const test_case =
+ new TestCase(test_case_name, set_up_tc, tear_down_tc);
+
+ // Is this a death test case?
+ if (String(test_case_name).EndsWith("DeathTest")) {
+ // Yes. Inserts the test case after the last death test case
+ // defined so far.
+ node = test_cases_.InsertAfter(last_death_test_case_, test_case);
+ last_death_test_case_ = node;
+ } else {
+ // No. Appends to the end of the list.
+ test_cases_.PushBack(test_case);
+ node = test_cases_.Last();
+ }
+ }
+
+ // Returns the TestCase found.
+ return node->element();
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the List::ForEach() method.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns 0 if all tests are successful, or 1 otherwise. If any
+// exception is thrown during a test on Windows, this test is
+// considered to be failed, but the rest of the tests will still be
+// run. (We disable exceptions on Linux and Mac OS X, so the issue
+// doesn't apply there.)
+int UnitTestImpl::RunAllTests() {
+ // True iff Google Test is initialized before RUN_ALL_TESTS() is called.
+ const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();
+
+ // Lists all the tests and exits if the --gtest_list_tests
+ // flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ ListAllTests();
+ return 0;
+ }
+
+ // True iff we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#ifdef GTEST_HAS_DEATH_TEST
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif // GTEST_HAS_DEATH_TEST
+
+ UnitTestEventListenerInterface * const printer = result_printer();
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests() > 0;
+ // True iff at least one test has failed.
+ bool failed = false;
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool forever = repeat < 0;
+ for (int i = 0; forever || i != repeat; i++) {
+ if (repeat != 1) {
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);
+ }
+
+ // Tells the unit test event listener that the tests are about to
+ // start.
+ printer->OnUnitTestStart(parent_);
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ // Runs each test case if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ printer->OnGlobalSetUpStart(parent_);
+ environments_.ForEach(SetUpEnvironment);
+ printer->OnGlobalSetUpEnd(parent_);
+
+ // Runs the tests only if there was no fatal failure during global
+ // set-up.
+ if (!Test::HasFatalFailure()) {
+ test_cases_.ForEach(TestCase::RunTestCase);
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ printer->OnGlobalTearDownStart(parent_);
+ environments_in_reverse_order_.ForEach(TearDownEnvironment);
+ printer->OnGlobalTearDownEnd(parent_);
+ }
+
+ elapsed_time_ = GetTimeInMillis() - start;
+
+ // Tells the unit test event listener that the tests have just
+ // finished.
+ printer->OnUnitTestEnd(parent_);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+ ClearResult();
+ }
+
+ if (!gtest_is_initialized_before_run_all_tests) {
+ ColoredPrintf(
+ COLOR_RED, "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
+ "This test program did NOT call %s() before calling RUN_ALL_TESTS(). "
+ "This is INVALID. Soon " GTEST_NAME
+ " will start to enforce the valid usage. "
+ "Please fix it ASAP, or IT WILL START TO FAIL.\n",
+ "testing::ParseGTestFlags"
+ ); // NOLINT
+ }
+
+ // Returns 0 if all tests passed, or 1 other wise.
+ return failed ? 1 : 0;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests() {
+ int num_runnable_tests = 0;
+ for (const internal::ListNode<TestCase *> *test_case_node =
+ test_cases_.Head();
+ test_case_node != NULL;
+ test_case_node = test_case_node->next()) {
+ TestCase * const test_case = test_case_node->element();
+ const String &test_case_name = test_case->name();
+ test_case->set_should_run(false);
+
+ for (const internal::ListNode<TestInfo *> *test_info_node =
+ test_case->test_info_list().Head();
+ test_info_node != NULL;
+ test_info_node = test_info_node->next()) {
+ TestInfo * const test_info = test_info_node->element();
+ const String test_name(test_info->name());
+ // A test is disabled if test case name or test name matches
+ // kDisableTestPattern.
+ const bool is_disabled =
+ internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern,
+ test_case_name.c_str()) ||
+ internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern,
+ test_name.c_str());
+ test_info->impl()->set_is_disabled(is_disabled);
+
+ const bool should_run = !is_disabled &&
+ internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+ test_name);
+ test_info->impl()->set_should_run(should_run);
+ test_case->set_should_run(test_case->should_run() || should_run);
+ if (should_run) {
+ num_runnable_tests++;
+ }
+ }
+ }
+ return num_runnable_tests;
+}
+
+// Lists all tests by name.
+void UnitTestImpl::ListAllTests() {
+ for (const internal::ListNode<TestCase*>* test_case_node = test_cases_.Head();
+ test_case_node != NULL;
+ test_case_node = test_case_node->next()) {
+ const TestCase* const test_case = test_case_node->element();
+
+ // Prints the test case name following by an indented list of test nodes.
+ printf("%s.\n", test_case->name());
+
+ for (const internal::ListNode<TestInfo*>* test_info_node =
+ test_case->test_info_list().Head();
+ test_info_node != NULL;
+ test_info_node = test_info_node->next()) {
+ const TestInfo* const test_info = test_info_node->element();
+
+ printf(" %s\n", test_info->name());
+ }
+ }
+ fflush(stdout);
+}
+
+// Sets the unit test result printer.
+//
+// Does nothing if the input and the current printer object are the
+// same; otherwise, deletes the old printer object and makes the
+// input the current printer.
+void UnitTestImpl::set_result_printer(
+ UnitTestEventListenerInterface* result_printer) {
+ if (result_printer_ != result_printer) {
+ delete result_printer_;
+ result_printer_ = result_printer;
+ }
+}
+
+// Returns the current unit test result printer if it is not NULL;
+// otherwise, creates an appropriate result printer, makes it the
+// current printer, and returns it.
+UnitTestEventListenerInterface* UnitTestImpl::result_printer() {
+ if (result_printer_ != NULL) {
+ return result_printer_;
+ }
+
+#ifdef GTEST_HAS_DEATH_TEST
+ if (internal_run_death_test_flag_.get() != NULL) {
+ result_printer_ = new NullUnitTestResultPrinter;
+ return result_printer_;
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater;
+ const String& output_format = internal::UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ repeater->AddListener(new XmlUnitTestResultPrinter(
+ internal::UnitTestOptions::GetOutputFile().c_str()));
+ } else if (output_format != "") {
+ printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+ output_format.c_str());
+ fflush(stdout);
+ }
+ repeater->AddListener(new PrettyUnitTestResultPrinter);
+ result_printer_ = repeater;
+ return result_printer_;
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter) {
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+ if (os_stack_trace_getter_ == NULL) {
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+internal::TestResult* UnitTestImpl::current_test_result() {
+ return current_test_info_ ?
+ current_test_info_->impl()->result() : &ad_hoc_test_result_;
+}
+
+// TestInfoImpl constructor.
+TestInfoImpl::TestInfoImpl(TestInfo* parent,
+ const char* test_case_name,
+ const char* name,
+ TypeId fixture_class_id,
+ TestMaker maker) :
+ parent_(parent),
+ test_case_name_(String(test_case_name)),
+ name_(String(name)),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ maker_(maker) {
+}
+
+// TestInfoImpl destructor.
+TestInfoImpl::~TestInfoImpl() {
+}
+
+} // namespace internal
+
+namespace internal {
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+ const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX.
+ const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX, flag);
+ const size_t flag_len = flag_str.GetLength();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// The internal implementation of ParseGTestFlags().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void ParseGTestFlagsImpl(int* argc, CharType** argv) {
+ g_parse_gtest_flags_called = true;
+ if (*argc <= 0) return;
+
+#ifdef GTEST_HAS_DEATH_TEST
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ for (int i = 1; i != *argc; i++) {
+ const String arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ // Do we see a Google Test flag?
+ if (ParseBoolFlag(arg, kBreakOnFailureFlag,
+ &GTEST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ &GTEST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ &GTEST_FLAG(death_test_style)) ||
+ ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ &GTEST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+ ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat))
+ ) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ }
+ }
+}
+
+} // namespace internal
+
+// Parses a command line for the flags that Google Test recognizes.
+// Whenever a Google Test flag is seen, it is removed from argv, and *argc
+// is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+void ParseGTestFlags(int* argc, char** argv) {
+ internal::g_executable_path = argv[0];
+ internal::ParseGTestFlagsImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+#ifdef GTEST_OS_WINDOWS
+void ParseGTestFlags(int* argc, wchar_t** argv) {
+ // g_executable_path uses normal characters rather than wide chars, so call
+ // StreamableToString to convert argv[0] to normal characters (utf8 encoding).
+ internal::g_executable_path = internal::StreamableToString(argv[0]);
+ internal::ParseGTestFlagsImpl(argc, argv);
+}
+#endif // GTEST_OS_WINDOWS
+
+} // namespace testing
diff --git a/src/gtest/gtest.h b/src/gtest/gtest.h
new file mode 100644
index 00000000..4e3d7bcb
--- /dev/null
+++ b/src/gtest/gtest.h
@@ -0,0 +1,1243 @@
+// 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: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#ifndef GTEST_NOT_MAC_FRAMEWORK_MODE
+// Protobuf never uses gTest in "mac framework mode".
+#define GTEST_NOT_MAC_FRAMEWORK_MODE
+#endif
+
+// The following platform macros are used throughout Google Test:
+// _WIN32_WCE Windows CE (set in project files)
+// __SYMBIAN32__ Symbian (set by Symbian tool chain)
+//
+// Note that even though _MSC_VER and _WIN32_WCE really indicate a compiler
+// and a Win32 implementation, respectively, we use them to indicate the
+// combination of compiler - Win 32 API - C library, since the code currently
+// only supports:
+// Windows proper with Visual C++ and MS C library (_MSC_VER && !_WIN32_WCE) and
+// Windows Mobile with Visual C++ and no C library (_WIN32_WCE).
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes
+// will be in the framework headers folder along with gtest.h. Define
+// GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on the
+// Mac and are not using it as a framework. More info on frameworks
+// available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-death-test.h" // NOLINT
+#include "gtest-internal.h" // NOLINT
+#include "gtest-message.h" // NOLINT
+#include "gtest-string.h" // NOLINT
+#include "gtest_prod.h" // NOLINT
+#else
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest-message.h>
+#include <gtest/gtest_prod.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+// Depending on the platform, different string classes are available.
+// On Windows, ::std::string compiles only when exceptions are
+// enabled. On Linux, in addition to ::std::string, Google also makes
+// use of class ::string, which has the same interface as
+// ::std::string, but has a different implementation.
+//
+// The user can tell us whether ::std::string is available in his
+// environment by defining the macro GTEST_HAS_STD_STRING to either 1
+// or 0 on the compiler command line. He can also define
+// GTEST_HAS_GLOBAL_STRING to 1 to indicate that ::string is available
+// AND is a distinct type to ::std::string, or define it to 0 to
+// indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_STD_STRING to 1 and
+// GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_STD_STRING and/or
+// GTEST_HAS_GLOBAL_STRING, they are defined heuristically.
+
+namespace testing {
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32(stack_trace_depth);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool(show_internal_stack_frames);
+
+// The possible outcomes of a test part (i.e. an assertion or an
+// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+enum TestPartResultType {
+ TPRT_SUCCESS, // Succeeded.
+ TPRT_NONFATAL_FAILURE, // Failed but the test can continue.
+ TPRT_FATAL_FAILURE // Failed and the test should be terminated.
+};
+
+namespace internal {
+
+class GTestFlagSaver;
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared in gtest-internal.h but defined here, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that described how it failed.
+//
+// This class is useful for defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// The constructor of AssertionResult is private. To create an
+// instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// For example, in order to be able to write:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you just need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0) return testing::AssertionSuccess();
+//
+// Message msg;
+// msg << "Expected: " << expr << " is even\n"
+// << " Actual: it's " << n;
+// return testing::AssertionFailure(msg);
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+class AssertionResult {
+ public:
+ // Declares factory functions for making successful and failed
+ // assertion results as friends.
+ friend AssertionResult AssertionSuccess();
+ friend AssertionResult AssertionFailure(const Message&);
+
+ // Returns true iff the assertion succeeded.
+ operator bool() const { return failure_message_.c_str() == NULL; } // NOLINT
+
+ // Returns the assertion's failure message.
+ const char* failure_message() const { return failure_message_.c_str(); }
+
+ private:
+ // The default constructor. It is used when the assertion succeeded.
+ AssertionResult() {}
+
+ // The constructor used when the assertion failed.
+ explicit AssertionResult(const internal::String& failure_message);
+
+ // Stores the assertion's failure message.
+ internal::String failure_message_;
+};
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { ... }
+// virtual void TearDown() { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class Test {
+ public:
+ friend class internal::TestInfoImpl;
+
+ // Defines types for pointers to functions that set up and tear down
+ // a test case.
+ typedef void (*SetUpTestCaseFunc)();
+ typedef void (*TearDownTestCaseFunc)();
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Returns true iff the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Logs a property for the current test. Only the last value for a given
+ // key is remembered.
+ // These are public static so they can be called from utility functions
+ // that are not members of the test fixture.
+ // The arguments are const char* instead strings, as Google Test is used
+ // on platforms where string doesn't compile.
+ //
+ // Note that a driving consideration for these RecordProperty methods
+ // was to produce xml output suited to the Greenspan charting utility,
+ // which at present will only chart values that fit in a 32-bit int. It
+ // is the user's responsibility to restrict their values to 32-bit ints
+ // if they intend them to be used with Greenspan.
+ static void RecordProperty(const char* key, const char* value);
+ static void RecordProperty(const char* key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true iff the current test has the same fixture class as
+ // the first test in the current test case.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Uses a GTestFlagSaver to save and restore all Google Test flags.
+ const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+ // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if a user declares void Setup() in his test
+ // fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if a user calls it from his test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN(Test);
+};
+
+
+// Defines the type of a function pointer that creates a Test object
+// when invoked.
+typedef Test* (*TestMaker)();
+
+
+// A TestInfo object stores the following information about a test:
+//
+// Test case name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class TestInfo {
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Creates a TestInfo object and registers it with the UnitTest
+ // singleton; returns the created object.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // name: name of the test
+ // fixture_class_id: ID of the test fixture class
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // maker: pointer to the function that creates a test object
+ //
+ // This is public only because it's needed by the TEST and TEST_F macros.
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ static TestInfo* MakeAndRegisterInstance(
+ const char* test_case_name,
+ const char* name,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestMaker maker);
+
+ // Returns the test case name.
+ const char* test_case_name() const;
+
+ // Returns the test name.
+ const char* name() const;
+
+ // Returns true if this test should run.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test case Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const;
+
+ // Returns the result of the test.
+ const internal::TestResult* result() const;
+ private:
+#ifdef GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif
+ friend class internal::TestInfoImpl;
+ friend class internal::UnitTestImpl;
+ friend class Test;
+ friend class TestCase;
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count();
+
+ // Accessors for the implementation object.
+ internal::TestInfoImpl* impl() { return impl_; }
+ const internal::TestInfoImpl* impl() const { return impl_; }
+
+ // Constructs a TestInfo object.
+ TestInfo(const char* test_case_name, const char* name,
+ internal::TypeId fixture_class_id, TestMaker maker);
+
+ // An opaque implementation object.
+ internal::TestInfoImpl* impl_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(TestInfo);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment {
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// A UnitTest consists of a list of TestCases.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class UnitTest {
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ void AddTestPartResult(TestPartResultType result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace);
+
+ // Adds a TestProperty to the current TestResult object. If the result already
+ // contains a property with the same key, the value will be updated.
+ void RecordPropertyForCurrentTest(const char* key, const char* value);
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT;
+
+ // Returns the TestCase object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestCase* current_test_case() const;
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const;
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+ private:
+ // ScopedTrace is a friend as it needs to modify the per-thread
+ // trace stack, which is a private member of UnitTest.
+ friend class internal::ScopedTrace;
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace();
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Parses a command line for the flags that Google Test recognizes.
+// Whenever a Google Test flag is seen, it is removed from argv, and *argc
+// is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+void ParseGTestFlags(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+#ifdef GTEST_OS_WINDOWS
+void ParseGTestFlags(int* argc, wchar_t** argv);
+#endif // GTEST_OS_WINDOWS
+
+namespace internal {
+
+// These overloaded versions handle ::std::string and ::std::wstring.
+#if GTEST_HAS_STD_STRING
+inline String FormatForFailureMessage(const ::std::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+#endif // GTEST_HAS_STD_STRING
+#if GTEST_HAS_STD_WSTRING
+inline String FormatForFailureMessage(const ::std::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// These overloaded versions handle ::string and ::wstring.
+#if GTEST_HAS_GLOBAL_STRING
+inline String FormatForFailureMessage(const ::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+inline String FormatForFailureMessage(const ::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char*, and print it as a C string when it is compared against an
+// std::string object, for example.
+//
+// The default implementation ignores the type of the other operand.
+// Some specialized versions are used to handle formatting wide or
+// narrow C strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+String FormatForComparisonFailureMessage(const T1& value,
+ const T2& /* other_operand */) {
+ return FormatForFailureMessage(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ. The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal. The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal.
+template <>
+class EqHelper<true> {
+ public:
+ // We define two overloaded versions of Compare(). The first
+ // version will be picked when the second argument to ASSERT_EQ() is
+ // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+ // EXPECT_EQ(false, a_bool).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // This version will be picked when the second argument to
+ // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ T2* actual) {
+ // We already know that 'expected' is a null pointer.
+ return CmpHelperEQ(expected_expression, actual_expression,
+ static_cast<T2*>(NULL), actual);
+ }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+#endif // GTEST_HAS_STD_STRING
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+ const char* actual_expression,
+ RawType expected,
+ RawType actual) {
+ const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ StrStream expected_ss;
+ expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << expected;
+
+ StrStream actual_ss;
+ actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << actual;
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ StrStreamToString(&expected_ss),
+ StrStreamToString(&actual_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class AssertHelper {
+ public:
+ // Constructor.
+ AssertHelper(TestPartResultType type, const char* file, int line,
+ const char* message);
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE macro below.
+ void operator=(const Message& message) const;
+ private:
+ TestPartResultType const type_;
+ const char* const file_;
+ int const line_;
+ String const message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(AssertHelper);
+};
+
+} // namespace internal
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+//
+// Examples:
+//
+// EXPECT_TRUE(server.StatusIsOK());
+// ASSERT_FALSE(server.HasPendingRequest(port))
+// << "There are still pending requests " << "on port " << port;
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE("Failed")
+
+// Generates a fatal failure with a generic message.
+#define FAIL() GTEST_FATAL_FAILURE("Failed")
+
+// Generates a success with a generic message.
+#define SUCCEED() GTEST_SUCCESS("Succeeded")
+
+// Boolean assertions.
+#define EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE)
+#define EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE)
+#define ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE)
+#define ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest_pred_impl.h" // NOLINT
+#else
+#include <gtest/gtest_pred_impl.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(5, Foo());
+// EXPECT_EQ(NULL, a_pointer);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL(expected)>::Compare, \
+ expected, actual)
+#define EXPECT_NE(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define ASSERT_EQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL(expected)>::Compare, \
+ expected, actual)
+#define ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// C String Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#ifdef GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the expected result
+// and the actual result with both a human-readable string representation of
+// the error, if available, as well as the hex result code.
+#define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, ::testing::Message() << (message))
+
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test". For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+#define TEST(test_case_name, test_name)\
+ GTEST_TEST(test_case_name, test_name, ::testing::Test)
+
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name. The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier. The user should put
+// his test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(0, a_.size());
+// EXPECT_EQ(1, b_.size());
+// }
+
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST(test_fixture, test_name, test_fixture)
+
+// Use this macro in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by ParseGTestFlags().
+
+#define RUN_ALL_TESTS()\
+ (::testing::UnitTest::GetInstance()->Run())
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/src/gtest/gtest_main.cc b/src/gtest/gtest_main.cc
new file mode 100644
index 00000000..c216bd2d
--- /dev/null
+++ b/src/gtest/gtest_main.cc
@@ -0,0 +1,39 @@
+// Copyright 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.
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ std::cout << "Running main() from gtest_main.cc\n";
+
+ testing::ParseGTestFlags(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/gtest/gtest_pred_impl.h b/src/gtest/gtest_pred_impl.h
new file mode 100644
index 00000000..984f7930
--- /dev/null
+++ b/src/gtest/gtest_pred_impl.h
@@ -0,0 +1,368 @@
+// Copyright 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.
+
+// This file is AUTOMATICALLY GENERATED on 06/22/2008 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1) {
+ if (pred(v1)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1(pred_format, v1, on_failure)\
+ GTEST_ASSERT(pred_format(#v1, v1),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1(pred, v1, on_failure)\
+ GTEST_ASSERT(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1(pred_format, v1, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1(pred, v1, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1(pred_format, v1, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1(pred, v1, GTEST_FATAL_FAILURE)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2) {
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT(pred_format(#v1, #v2, v1, v2),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2(pred, v1, v2, on_failure)\
+ GTEST_ASSERT(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2(pred_format, v1, v2, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2(pred, v1, v2, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2(pred_format, v1, v2, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2(pred, v1, v2, GTEST_FATAL_FAILURE)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT(pred_format(#v1, #v2, #v3, v1, v2, v3),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3(pred, v1, v2, v3, GTEST_FATAL_FAILURE)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ", "
+ << e5 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4
+ << "\n" << e5 << " evaluates to " << v5;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE)
+
+
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/src/gtest/gtest_prod.h b/src/gtest/gtest_prod.h
new file mode 100644
index 00000000..da80ddc6
--- /dev/null
+++ b/src/gtest/gtest_prod.h
@@ -0,0 +1,58 @@
+// Copyright 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.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+// // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/src/gtest/internal/gtest-death-test-internal.h b/src/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 00000000..b49c6e47
--- /dev/null
+++ b/src/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,201 @@
+// 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.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class DeathTest {
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the two reasons that a test might be aborted.
+ enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN(DeathTest);
+};
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status);
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+#define GTEST_DEATH_TEST(statement, predicate, regex, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER \
+ if (true) { \
+ const ::testing::internal::RE& gtest_regex = (regex); \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != NULL) { \
+ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+ gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel \
+ gtest_sentinel(gtest_dt); \
+ { statement; } \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN(gtest_label_, __LINE__): \
+ fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// A struct representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+struct InternalRunDeathTestFlag {
+ String file;
+ int line;
+ int index;
+ int status_fd;
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/src/gtest/internal/gtest-filepath.h b/src/gtest/internal/gtest-filepath.h
new file mode 100644
index 00000000..6f63718d
--- /dev/null
+++ b/src/gtest/internal/gtest-filepath.h
@@ -0,0 +1,168 @@
+// 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.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in testing/base/internal/gtest-internal.h
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-string.h" // NOLINT
+#else
+#include <gtest/internal/gtest-string.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class FilePath {
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+ explicit FilePath(const char* pathname) : pathname_(pathname) { }
+ explicit FilePath(const String& pathname) : pathname_(pathname) { }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ String ToString() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ private:
+ String pathname_;
+
+ // Don't implement operator= because it is banned by the style guide.
+ FilePath& operator=(const FilePath& rhs);
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/src/gtest/internal/gtest-internal.h b/src/gtest/internal/gtest-internal.h
new file mode 100644
index 00000000..2be1b4ac
--- /dev/null
+++ b/src/gtest/internal/gtest-internal.h
@@ -0,0 +1,569 @@
+// 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.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-port.h" // NOLINT
+#else
+#include <gtest/internal/gtest-port.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+#ifdef GTEST_OS_LINUX
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#include <iomanip> // NOLINT
+#include <limits> // NOLINT
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-string.h" // NOLINT
+#include "gtest-filepath.h" // NOLINT
+#else
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-filepath.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN(foo, bar) GTEST_CONCAT_TOKEN_IMPL(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL(foo, bar) foo ## bar
+
+// Google Test defines the testing::Message class to allow construction of
+// test messages via the << operator. The idea is that anything
+// streamable to std::ostream can be streamed to a testing::Message.
+// This allows a user to use his own types in Google Test assertions by
+// overloading the << operator.
+//
+// util/gtl/stl_logging-inl.h overloads << for STL containers. These
+// overloads cannot be defined in the std namespace, as that will be
+// undefined behavior. Therefore, they are defined in the global
+// namespace instead.
+//
+// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+// overloads are visible in either the std namespace or the global
+// namespace, but not other namespaces, including the testing
+// namespace which Google Test's Message class is in.
+//
+// To allow STL containers (and other types that has a << operator
+// defined in the global namespace) to be used in Google Test assertions,
+// testing::Message must access the custom << operator from the global
+// namespace. Hence this helper function.
+//
+// Note: Jeffrey Yasskin suggested an alternative fix by "using
+// ::operator<<;" in the definition of Message's operator<<. That fix
+// doesn't require a helper function, but unfortunately doesn't
+// compile with MSVC.
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+ *os << val;
+}
+
+namespace testing {
+
+// Forward declaration of classes.
+
+class Message; // Represents a failure message.
+class TestCase; // A collection of related tests.
+class TestPartResult; // Result of a test part.
+class TestInfo; // Information about a test.
+class UnitTest; // A collection of test cases.
+class UnitTestEventListenerInterface; // Listens to Google Test events.
+class AssertionResult; // Result of an assertion.
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class ScopedTrace; // Implements scoped trace.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class TestResult; // Result of a single Test.
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+template <typename E> class List; // A generic list.
+template <typename E> class ListNode; // A node in a generic list.
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant). Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler. These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise. Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal. Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2]; // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef __SYMBIAN32__ // Symbian
+// Passing non-POD classes through ellipsis (...) crashes the ARM compiler.
+// The Nokia Symbian compiler tries to instantiate a copy constructor for
+// objects passed through ellipsis (...), failing for uncopyable objects.
+// Hence we define this to false (and lose support for NULL detection).
+#define GTEST_IS_NULL_LITERAL(x) false
+#else // ! __SYMBIAN32__
+#define GTEST_IS_NULL_LITERAL(x) \
+ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif // __SYMBIAN32__
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg);
+
+// A helper class for creating scoped traces in user programs.
+class ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+ ScopedTrace(const char* file, int line, const Message& message);
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+// Formats a value to be used in a failure message.
+
+#ifdef __SYMBIAN32__
+
+// These are needed as the Nokia Symbian Compiler cannot decide between
+// const T& and const T* in a function template. The Nokia compiler _can_
+// decide between class template specializations for T and T*, so a
+// tr1::type_traits-like is_pointer works, and we can overload on that.
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatValueForFailureMessage(internal::true_type dummy,
+ T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+template <typename T>
+inline String FormatValueForFailureMessage(internal::false_type dummy,
+ const T& value) {
+ return StreamableToString(value);
+}
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return FormatValueForFailureMessage(
+ typename internal::is_pointer<T>::type(), value);
+}
+
+#else
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return StreamableToString(value);
+}
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatForFailureMessage(T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+#endif // __SYMBIAN32__
+
+// These overloaded versions handle narrow and wide characters.
+String FormatForFailureMessage(char ch);
+String FormatForFailureMessage(wchar_t wchar);
+
+// When this operand is a const char* or char*, and the other operand
+// is a ::std::string or ::string, we print this operand as a C string
+// rather than a pointer. We do the same for wide strings.
+
+// This internal macro is used to avoid duplicated code.
+#define GTEST_FORMAT_IMPL(operand2_type, operand1_printer)\
+inline String FormatForComparisonFailureMessage(\
+ operand2_type::value_type* str, const operand2_type& operand2) {\
+ return operand1_printer(str);\
+}\
+inline String FormatForComparisonFailureMessage(\
+ const operand2_type::value_type* str, const operand2_type& operand2) {\
+ return operand1_printer(str);\
+}
+
+#if GTEST_HAS_STD_STRING
+GTEST_FORMAT_IMPL(::std::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_STD_STRING
+#if GTEST_HAS_STD_WSTRING
+GTEST_FORMAT_IMPL(::std::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_FORMAT_IMPL(::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_FORMAT_IMPL(::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#undef GTEST_FORMAT_IMPL
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case);
+
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
+ static const size_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) : value_(x) {}
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.bits_ = bits;
+ return fp.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits &bits() const { return bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & bits_; }
+
+ // Returns true iff this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true iff this number is at most kMaxUlps ULP's away from
+ // rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps;
+ }
+
+ private:
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+ const Bits &sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ union {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef void* TypeId;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+inline TypeId GetTypeId() {
+ static bool dummy = false;
+ // The compiler is required to create an instance of the static
+ // variable dummy for each T used to instantiate the template.
+ // Therefore, the address of dummy is guaranteed to be unique.
+ return &dummy;
+}
+
+#ifdef GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT
+AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+} // namespace internal
+} // namespace testing
+
+#define GTEST_MESSAGE(message, result_type) \
+ ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \
+ = ::testing::Message()
+
+#define GTEST_FATAL_FAILURE(message) \
+ return GTEST_MESSAGE(message, ::testing::TPRT_FATAL_FAILURE)
+
+#define GTEST_NONFATAL_FAILURE(message) \
+ GTEST_MESSAGE(message, ::testing::TPRT_NONFATAL_FAILURE)
+
+#define GTEST_SUCCESS(message) \
+ GTEST_MESSAGE(message, ::testing::TPRT_SUCCESS)
+
+#define GTEST_TEST_BOOLEAN(boolexpr, booltext, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER \
+ if (boolexpr) \
+ ; \
+ else \
+ fail("Value of: " booltext "\n Actual: " #actual "\nExpected: " #expected)
+
+// Helper macro for defining tests.
+#define GTEST_TEST(test_case_name, test_name, parent_class)\
+class test_case_name##_##test_name##_Test : public parent_class {\
+ public:\
+ test_case_name##_##test_name##_Test() {}\
+ static ::testing::Test* NewTest() {\
+ return new test_case_name##_##test_name##_Test;\
+ }\
+ private:\
+ virtual void TestBody();\
+ static ::testing::TestInfo* const test_info_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN(test_case_name##_##test_name##_Test);\
+};\
+\
+::testing::TestInfo* const test_case_name##_##test_name##_Test::test_info_ =\
+ ::testing::TestInfo::MakeAndRegisterInstance(\
+ #test_case_name, \
+ #test_name, \
+ ::testing::internal::GetTypeId< parent_class >(), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ test_case_name##_##test_name##_Test::NewTest);\
+void test_case_name##_##test_name##_Test::TestBody()
+
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/src/gtest/internal/gtest-port.h b/src/gtest/internal/gtest-port.h
new file mode 100644
index 00000000..36d5a149
--- /dev/null
+++ b/src/gtest/internal/gtest-port.h
@@ -0,0 +1,596 @@
+// 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.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. They are subject to change without notice. DO NOT USE
+// THEM IN USER CODE.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+#ifndef GTEST_NOT_MAC_FRAMEWORK_MODE
+// Protobuf never uses gTest in "mac framework mode".
+#define GTEST_NOT_MAC_FRAMEWORK_MODE
+#endif
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior:
+//
+// GTEST_HAS_STD_STRING - Define it to 1/0 to indicate that
+// std::string does/doesn't work (Google Test can be
+// used where std::string is unavailable). Leave
+// it undefined to let Google Test define it.
+// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define ::string,
+// which is different to std::string). Leave it
+// undefined to let Google Test define it.
+
+// This header defines the following utilities:
+//
+// Macros indicating the name of the Google C++ Testing Framework project:
+// GTEST_NAME - a string literal of the project name.
+// GTEST_FLAG_PREFIX - a string literal of the prefix all Google
+// Test flag names share.
+// GTEST_FLAG_PREFIX_UPPER - a string literal of the prefix all Google
+// Test flag names share, in upper case.
+//
+// Macros indicating the current platform:
+// GTEST_OS_LINUX - defined iff compiled on Linux.
+// GTEST_OS_MAC - defined iff compiled on Mac OS X.
+// GTEST_OS_WINDOWS - defined iff compiled on Windows.
+// Note that it is possible that none of the GTEST_OS_ macros are defined.
+//
+// Macros indicating available Google Test features:
+// GTEST_HAS_DEATH_TEST - defined iff death tests are supported.
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED - declares that a class' instances don't have to
+// be used.
+// GTEST_DISALLOW_COPY_AND_ASSIGN() - disables copy ctor and operator=.
+// GTEST_MUST_USE_RESULT - declares that a function's result must be used.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+//
+// Template meta programming:
+// is_pointer - as in TR1; needed on Symbian only.
+//
+// Smart pointers:
+// scoped_ptr - as in TR2.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax. Not available on
+// Windows.
+//
+// Logging:
+// GTEST_LOG() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stderr capturing:
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// Int32, UInt32, Int64, UInt64, TimeInMillis
+// - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_FLAG() - references a flag.
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an Int32 environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define GTEST_NAME "Google Test"
+#define GTEST_FLAG_PREFIX "gtest_"
+#define GTEST_FLAG_PREFIX_UPPER "GTEST_"
+
+// Determines the platform on which Google Test is compiled.
+#ifdef _MSC_VER
+// TODO(kenton): GTEST_OS_WINDOWS is currently used to mean both "The OS is
+// Windows" and "The compiler is MSVC". These meanings really should be
+// separated in order to better support Windows compilers other than MSVC.
+// Then again, the macro _WIN32 is already a good way to check for the first
+// case and _MSC_VER is a good way to check for the latter, so maybe
+// GTEST_OS_WINDOWS should be removed?
+#define GTEST_OS_WINDOWS
+#elif defined __APPLE__
+#define GTEST_OS_MAC
+#elif defined __linux__
+#define GTEST_OS_LINUX
+#endif // _MSC_VER
+
+// Determines whether ::std::string and ::string are available.
+
+#ifndef GTEST_HAS_STD_STRING
+// The user didn't tell us whether ::std::string is available, so we
+// need to figure it out.
+
+#ifdef GTEST_OS_WINDOWS
+// Assumes that exceptions are enabled by default.
+#ifndef _HAS_EXCEPTIONS
+#define _HAS_EXCEPTIONS 1
+#endif // _HAS_EXCEPTIONS
+// GTEST_HAS_EXCEPTIONS is non-zero iff exceptions are enabled. It is
+// always defined, while _HAS_EXCEPTIONS is defined only on Windows.
+#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+// On Windows, we can use ::std::string if the compiler version is VS
+// 2005 or above, or if exceptions are enabled.
+#define GTEST_HAS_STD_STRING ((_MSC_VER >= 1400) || GTEST_HAS_EXCEPTIONS)
+#else // We are on Linux or Mac OS.
+#define GTEST_HAS_EXCEPTIONS 0
+#define GTEST_HAS_STD_STRING 1
+#endif // GTEST_OS_WINDOWS
+
+#endif // GTEST_HAS_STD_STRING
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+#define GTEST_HAS_GLOBAL_STRING 0
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING
+#include <string> // NOLINT
+#endif // GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_STD_STRING
+#include <sstream> // NOLINT
+#else
+#include <strstream> // NOLINT
+#endif // GTEST_HAS_STD_STRING
+
+// Determines whether to support death tests.
+#if GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX)
+#define GTEST_HAS_DEATH_TEST
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile if being #included first. Therefore it's important
+// that we #include it after <sys/types.h>.
+#include <regex.h>
+#include <vector>
+#include <fcntl.h>
+#include <sys/mman.h>
+#endif // GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX)
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER
+#else
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER switch (0) case 0: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct / class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED;
+#if defined(GTEST_OS_WINDOWS) || (defined(GTEST_OS_LINUX) && defined(SWIG))
+#define GTEST_ATTRIBUTE_UNUSED
+#else
+#define GTEST_ATTRIBUTE_UNUSED __attribute__ ((unused))
+#endif // GTEST_OS_WINDOWS || (GTEST_OS_LINUX && SWIG)
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN(type)\
+ type(const type &);\
+ void operator=(const type &)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT;
+#if defined(__GNUC__) \
+ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
+ && !defined(COMPILER_ICC)
+#define GTEST_MUST_USE_RESULT __attribute__ ((warn_unused_result))
+#else
+#define GTEST_MUST_USE_RESULT
+#endif // (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+class String;
+
+// std::strstream is deprecated. However, we have to use it on
+// Windows as std::stringstream won't compile on Windows when
+// exceptions are disabled. We use std::stringstream on other
+// platforms to avoid compiler warnings there.
+#if GTEST_HAS_STD_STRING
+typedef ::std::stringstream StrStream;
+#else
+typedef ::std::strstream StrStream;
+#endif // GTEST_HAS_STD_STRING
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+ explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+ ~scoped_ptr() { reset(); }
+
+ T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const { return ptr_; }
+
+ T* release() {
+ T* const ptr = ptr_;
+ ptr_ = NULL;
+ return ptr;
+ }
+
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ if (sizeof(T) > 0) { // Makes sure T is a complete type.
+ delete ptr_;
+ }
+ ptr_ = p;
+ }
+ }
+ private:
+ T* ptr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN(scoped_ptr);
+};
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// Defines RE. Currently only needed for death tests.
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Enxtended
+// Regular Expression syntax.
+class RE {
+ public:
+ // Constructs an RE from a string.
+#if GTEST_HAS_STD_STRING
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+ RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // Returns true iff str contains regular expression re.
+
+ // TODO(wan): make PartialMatch() work when str contains NUL
+ // characters.
+#if GTEST_HAS_STD_STRING
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+#endif // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+ static bool PartialMatch(const ::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+
+ // We use a const char* instead of a string, as Google Test may be used
+ // where string is not available. We also do not use Google Test's own
+ // String type here, in order to simplify dependencies between the
+ // files.
+ const char* pattern_;
+ regex_t regex_;
+ bool is_valid_;
+};
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines logging utilities:
+// GTEST_LOG() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+void GTestLog(GTestLogSeverity severity, const char* file,
+ int line, const char* msg);
+
+#define GTEST_LOG(severity, msg)\
+ ::testing::internal::GTestLog(\
+ ::testing::internal::GTEST_##severity, __FILE__, __LINE__, \
+ (::testing::Message() << (msg)).GetString().c_str())
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// Defines the stderr capturer:
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by ParseGTestFlags().
+extern ::std::vector<String> g_argvs;
+
+void CaptureStderr();
+// GTEST_HAS_DEATH_TEST implies we have ::std::string.
+::std::string GetCapturedStderr();
+const ::std::vector<String>& GetArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+ Mutex() {}
+ explicit Mutex(int unused) {}
+ void AssertHeld() const {}
+ enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 };
+};
+
+// We cannot call it MutexLock directly as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+// There's no portable way to detect the number of threads, so we just
+// return 0 to indicate that we cannot detect it.
+// CHANGED FOR PROTOBUF: The protobuf tests do not use multiple threads,
+// so we know there is one thread.
+inline size_t GetThreadCount() { return 1; }
+
+// Defines tr1::is_pointer (only needed for Symbian).
+
+#ifdef __SYMBIAN32__
+
+// Symbian does not have tr1::type_traits, so we define our own is_pointer
+// These are needed as the Nokia Symbian Compiler cannot decide between
+// const T& and const T* in a function template.
+
+template <bool bool_value>
+struct bool_constant {
+ typedef bool_constant<bool_value> type;
+ static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+#endif // __SYMBIAN32__
+
+// Defines BiggestInt as the biggest signed integer type the compiler
+// supports.
+
+#ifdef GTEST_OS_WINDOWS
+typedef __int64 BiggestInt;
+#else
+typedef long long BiggestInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// The maximum number a BiggestInt can represent. This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+ ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ // unsigned int has size 4 in both gcc and MSVC.
+ //
+ // As base/basictypes.h doesn't compile on Windows, we cannot use
+ // uint32, uint64, and etc here.
+ typedef int Int;
+ typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#ifdef GTEST_OS_WINDOWS
+ typedef __int64 Int;
+ typedef unsigned __int64 UInt;
+#else
+ typedef long long Int; // NOLINT
+ typedef unsigned long long UInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// A wrapper for getenv() that works on Linux, Windows, and Mac OS.
+inline const char* GetEnv(const char* name) {
+#ifdef _WIN32_WCE // We are on Windows CE.
+ // CE has no environment variables.
+ return NULL;
+#elif defined(GTEST_OS_WINDOWS) // We are on Windows proper.
+ // MSVC 8 deprecates getenv(), so we want to suppress warning 4996
+ // (deprecated function) there.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ return getenv(name);
+#pragma warning(pop) // Restores the warning state.
+#else // We are on Linux or Mac OS.
+ return getenv(name);
+#endif
+}
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool(name) extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32(name) \
+ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string(name) \
+ extern ::testing::internal::String GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool(name, default_val, doc) \
+ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32(name, default_val, doc) \
+ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string(name, default_val, doc) \
+ ::testing::internal::String GTEST_FLAG(name) = (default_val)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/src/gtest/internal/gtest-string.h b/src/gtest/internal/gtest-string.h
new file mode 100644
index 00000000..3d20c0fc
--- /dev/null
+++ b/src/gtest/internal/gtest-string.h
@@ -0,0 +1,280 @@
+// 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.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by testing/base/internal/gtest-internal.h.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#include <string.h>
+
+#if defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+// When using Google Test on the Mac as a framework, all the includes will be
+// in the framework headers folder along with gtest.h.
+// Define GTEST_NOT_MAC_FRAMEWORK_MODE if you are building Google Test on
+// the Mac and are not using it as a framework.
+// More info on frameworks available here:
+// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/
+// Concepts/WhatAreFrameworks.html.
+#include "gtest-port.h" // NOLINT
+#else
+#include <gtest/internal/gtest-port.h>
+#endif // defined(__APPLE__) && !defined(GTEST_NOT_MAC_FRAMEWORK_MODE)
+
+namespace testing {
+namespace internal {
+
+// String - a UTF-8 string class.
+//
+// We cannot use std::string as Microsoft's STL implementation in
+// Visual C++ 7.1 has problems when exception is disabled. There is a
+// hack to work around this, but we've seen cases where the hack fails
+// to work.
+//
+// Also, String is different from std::string in that it can represent
+// both NULL and the empty string, while std::string cannot represent
+// NULL.
+//
+// NULL and the empty string are considered different. NULL is less
+// than anything (including the empty string) except itself.
+//
+// This class only provides minimum functionality necessary for
+// implementing Google Test. We do not intend to implement a full-fledged
+// string class here.
+//
+// Since the purpose of this class is to provide a substitute for
+// std::string on platforms where it cannot be used, we define a copy
+// constructor and assignment operators such that we don't need
+// conditional compilation in a lot of places.
+//
+// In order to make the representation efficient, the d'tor of String
+// is not virtual. Therefore DO NOT INHERIT FROM String.
+class String {
+ public:
+ // Static utility methods
+
+ // Returns the input if it's not NULL, otherwise returns "(null)".
+ // This function serves two purposes:
+ //
+ // 1. ShowCString(NULL) has type 'const char *', instead of the
+ // type of NULL (which is int).
+ //
+ // 2. In MSVC, streaming a null char pointer to StrStream generates
+ // an access violation, so we need to convert NULL to "(null)"
+ // before streaming it.
+ static inline const char* ShowCString(const char* c_str) {
+ return c_str ? c_str : "(null)";
+ }
+
+ // Returns the input enclosed in double quotes if it's not NULL;
+ // otherwise returns "(null)". For example, "\"Hello\"" is returned
+ // for input "Hello".
+ //
+ // This is useful for printing a C string in the syntax of a literal.
+ //
+ // Known issue: escape sequences are not handled yet.
+ static String ShowCStringQuoted(const char* c_str);
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+ // Compares two C strings. Returns true iff they have the same content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static String ShowWideCString(const wchar_t* wide_c_str);
+
+ // Similar to ShowWideCString(), except that this function encloses
+ // the converted string in double quotes.
+ static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true iff they have the same
+ // content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Formats a list of arguments to a String, using the same format
+ // spec string as for printf.
+ //
+ // We do not use the StringPrintf class as it is not universally
+ // available.
+ //
+ // The result is limited to 4096 characters (including the tailing
+ // 0). If 4096 characters are not enough to format the input,
+ // "<buffer exceeded>" is returned.
+ static String Format(const char* format, ...);
+
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ String() : c_str_(NULL) {}
+
+ // Constructs a String by cloning a 0-terminated C string.
+ String(const char* c_str) : c_str_(NULL) { // NOLINT
+ *this = c_str;
+ }
+
+ // Constructs a String by copying a given number of chars from a
+ // buffer. E.g. String("hello", 3) will create the string "hel".
+ String(const char* buffer, size_t len);
+
+ // The copy c'tor creates a new copy of the string. The two
+ // String objects do not share content.
+ String(const String& str) : c_str_(NULL) {
+ *this = str;
+ }
+
+ // D'tor. String is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~String() { delete[] c_str_; }
+
+ // Returns true iff this is an empty string (i.e. "").
+ bool empty() const {
+ return (c_str_ != NULL) && (*c_str_ == '\0');
+ }
+
+ // Compares this with another String.
+ // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+ // if this is greater than rhs.
+ int Compare(const String& rhs) const;
+
+ // Returns true iff this String equals the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator==(const char* c_str) const {
+ return CStringEquals(c_str_, c_str);
+ }
+
+ // Returns true iff this String doesn't equal the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator!=(const char* c_str) const {
+ return !CStringEquals(c_str_, c_str);
+ }
+
+ // Returns true iff this String ends with the given suffix. *Any*
+ // String is considered to end with a NULL or empty suffix.
+ bool EndsWith(const char* suffix) const;
+
+ // Returns true iff this String ends with the given suffix, not considering
+ // case. Any String is considered to end with a NULL or empty suffix.
+ bool EndsWithCaseInsensitive(const char* suffix) const;
+
+ // Returns the length of the encapsulated string, or -1 if the
+ // string is NULL.
+ int GetLength() const {
+ return c_str_ ? static_cast<int>(strlen(c_str_)) : -1;
+ }
+
+ // Gets the 0-terminated C string this String object represents.
+ // The String object still owns the string. Therefore the caller
+ // should NOT delete the return value.
+ const char* c_str() const { return c_str_; }
+
+ // Sets the 0-terminated C string this String object represents.
+ // The old string in this object is deleted, and this object will
+ // own a clone of the input string. This function copies only up to
+ // length bytes (plus a terminating null byte), or until the first
+ // null byte, whichever comes first.
+ //
+ // This function works even when the c_str parameter has the same
+ // value as that of the c_str_ field.
+ void Set(const char* c_str, size_t length);
+
+ // Assigns a C string to this object. Self-assignment works.
+ const String& operator=(const char* c_str);
+
+ // Assigns a String object to this object. Self-assignment works.
+ const String& operator=(const String &rhs) {
+ *this = rhs.c_str_;
+ return *this;
+ }
+
+ private:
+ const char* c_str_;
+};
+
+// Streams a String to an ostream.
+inline ::std::ostream& operator <<(::std::ostream& os, const String& str) {
+ // We call String::ShowCString() to convert NULL to "(null)".
+ // Otherwise we'll get an access violation on Windows.
+ return os << String::ShowCString(str.c_str());
+}
+
+// Gets the content of the StrStream's buffer as a String. Each '\0'
+// character in the buffer is replaced with "\\0".
+String StrStreamToString(StrStream* stream);
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/vsprojects/config.h b/vsprojects/config.h
new file mode 100644
index 00000000..95befa10
--- /dev/null
+++ b/vsprojects/config.h
@@ -0,0 +1,21 @@
+/* protobuf config.h for MSVC. On other platforms, this is generated
+ * automatically by autoheader / autoconf / configure. */
+
+/* the location of <hash_map> */
+#define HASH_MAP_H <hash_map>
+
+/* the namespace of hash_map/hash_set */
+#if _MSC_VER < 1310
+#define HASH_NAMESPACE std
+#else
+#define HASH_NAMESPACE stdext
+#endif
+
+/* the location of <hash_set> */
+#define HASH_SET_H <hash_set>
+
+/* define if the compiler has hash_map */
+#define HAVE_HASH_MAP
+
+/* define if the compiler has hash_set */
+#define HAVE_HASH_SET
diff --git a/vsprojects/convert2008to2005.sh b/vsprojects/convert2008to2005.sh
new file mode 100755
index 00000000..60eccaf3
--- /dev/null
+++ b/vsprojects/convert2008to2005.sh
@@ -0,0 +1,20 @@
+#! /bin/sh -e
+
+# This script downgrades MSVC 2008 projects to MSVC 2005 projects, allowing
+# people with MSVC 2005 to open them. Otherwise, MSVC 2005 simply refuses to
+# open projects created with 2008. We run this as part of our release process.
+# If you obtained the code direct from version control and you want to use
+# MSVC 2005, you may have to run this manually. (Hint: Use Cygwin or MSYS.)
+
+for file in *.sln; do
+ echo "downgrading $file..."
+ sed -i -re 's/Format Version 10.00/Format Version 9.00/g;
+ s/Visual Studio 2008/Visual Studio 2005/g;' $file
+done
+
+for file in *.vcproj; do
+ echo "downgrading $file..."
+ sed -i -re 's/Version="9.00"/Version="8.00"/g;' $file
+done
+
+# Yes, really, that's it.
diff --git a/vsprojects/extract_includes.bat b/vsprojects/extract_includes.bat
new file mode 100755
index 00000000..85c4d92b
--- /dev/null
+++ b/vsprojects/extract_includes.bat
@@ -0,0 +1,36 @@
+md include
+md include\google
+md include\google\protobuf
+md include\google\protobuf\stubs
+md include\google\protobuf\io
+md include\google\protobuf\compiler
+md include\google\protobuf\compiler\cpp
+md include\google\protobuf\compiler\java
+md include\google\protobuf\compiler\python
+copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
+copy ..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h
+copy ..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h
+copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h
+copy ..\src\google\protobuf\dynamic_message.h include\google\protobuf\dynamic_message.h
+copy ..\src\google\protobuf\extension_set.h include\google\protobuf\extension_set.h
+copy ..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
+copy ..\src\google\protobuf\message.h include\google\protobuf\message.h
+copy ..\src\google\protobuf\reflection_ops.h include\google\protobuf\reflection_ops.h
+copy ..\src\google\protobuf\repeated_field.h include\google\protobuf\repeated_field.h
+copy ..\src\google\protobuf\service.h include\google\protobuf\service.h
+copy ..\src\google\protobuf\text_format.h include\google\protobuf\text_format.h
+copy ..\src\google\protobuf\unknown_field_set.h include\google\protobuf\unknown_field_set.h
+copy ..\src\google\protobuf\wire_format.h include\google\protobuf\wire_format.h
+copy ..\src\google\protobuf\wire_format_inl.h include\google\protobuf\wire_format_inl.h
+copy ..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
+copy ..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h
+copy ..\src\google\protobuf\io\tokenizer.h include\google\protobuf\io\tokenizer.h
+copy ..\src\google\protobuf\io\zero_copy_stream.h include\google\protobuf\io\zero_copy_stream.h
+copy ..\src\google\protobuf\io\zero_copy_stream_impl.h include\google\protobuf\io\zero_copy_stream_impl.h
+copy ..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h
+copy ..\src\google\protobuf\compiler\command_line_interface.h include\google\protobuf\compiler\command_line_interface.h
+copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
+copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
+copy ..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
+copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
+copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
diff --git a/vsprojects/libprotobuf.vcproj b/vsprojects/libprotobuf.vcproj
new file mode 100644
index 00000000..a6808968
--- /dev/null
+++ b/vsprojects/libprotobuf.vcproj
@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libprotobuf"
+ ProjectGUID="{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\io\coded_stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor.pb.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor_database.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\dynamic_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\extension_set.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\generated_message_reflection.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\hash.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\importer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\map-util.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\parser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\printer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\reflection_ops.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\repeated_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\scoped_memory_log.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\service.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stl_util-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\strutil.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\substitute.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\text_format.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\tokenizer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unknown_field_set.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\wire_format.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\wire_format_inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\io\coded_stream.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\common.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor_database.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\dynamic_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\extension_set.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\generated_message_reflection.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\hash.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\importer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\map-util.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\parser.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\printer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\reflection_ops.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\repeated_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\stl_util-inl.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\strutil.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\substitute.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\text_format.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\tokenizer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unknown_field_set.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\wire_format.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl.cc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj
new file mode 100644
index 00000000..b1a6b984
--- /dev/null
+++ b/vsprojects/libprotoc.vcproj
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libprotoc"
+ ProjectGUID="{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\compiler\code_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_extension.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_helpers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_service.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\python\python_generator.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\compiler\code_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_extension.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_generator.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_helpers.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_message_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\java\java_service.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\python\python_generator.cc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/protobuf.sln b/vsprojects/protobuf.sln
new file mode 100644
index 00000000..9523a864
--- /dev/null
+++ b/vsprojects/protobuf.sln
@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf", "libprotobuf.vcproj", "{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotoc", "libprotoc.vcproj", "{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "protoc.vcproj", "{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests.vcproj", "{4DF72760-C055-40A5-A77E-30A17E2AC2DB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
+ {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.Build.0 = Debug|Win32
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.ActiveCfg = Release|Win32
+ {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.Build.0 = Release|Win32
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.Build.0 = Debug|Win32
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.ActiveCfg = Release|Win32
+ {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.Build.0 = Release|Win32
+ {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.Build.0 = Debug|Win32
+ {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.ActiveCfg = Release|Win32
+ {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.Build.0 = Release|Win32
+ {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.Build.0 = Debug|Win32
+ {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.ActiveCfg = Release|Win32
+ {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/vsprojects/protoc.vcproj b/vsprojects/protoc.vcproj
new file mode 100644
index 00000000..17e8474e
--- /dev/null
+++ b/vsprojects/protoc.vcproj
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="protoc"
+ ProjectGUID="{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\compiler\main.cc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/readme.txt b/vsprojects/readme.txt
new file mode 100644
index 00000000..7f7278e0
--- /dev/null
+++ b/vsprojects/readme.txt
@@ -0,0 +1,71 @@
+This directory contains project files for compiling Protocol Buffers using
+MSVC. This is not the recommended way to do Protocol Buffer development --
+we prefer to develop under a Unix-like environment -- but it may be more
+accessible to those who primarily work with MSVC.
+
+Compiling and Installing
+========================
+
+1) Open protobuf.sln in Microsoft Visual Studio.
+2) Choose "Debug" or "Release" configuration as desired.
+3) From the Build menu, choose "Build Solution". Wait for compiling to finish.
+4) From a command shell, run tests.exe and check that all tests pass.
+5) Run extract_includes.bat to copy all the public headers into a separate
+ "include" directory (under the top-level package directory).
+6) Copy the contents of the include directory to wherever you want to put
+ headers.
+7) Copy protoc.exe and the two DLLs (libprotobuf and libprotoc) wherever you
+ put build tools.
+8) Copy libprotobuf.{lib,dll} and libprotoc.{lib,dll} wherever you put
+ libraries.
+
+DLLs and Distribution
+=====================
+
+When distributing your software to end users, we strongly recommend that you
+do NOT install libprotobuf.dll or libprotoc.dll to any shared location.
+Instead, keep these libraries next to your binaries, in your application's
+own install directory. C++ makes it very difficult to maintain binary
+compatibility between releases, so it is likely that future versions of these
+libraries will *not* be usable as drop-in replacements. The only reason we
+provide these libraries as DLLs rather than static libs is so that a program
+which is itself split into multiple DLLs can safely pass protocol buffer
+objects between them.
+
+If your project is itself a DLL intended for use by third-party software, we
+recommend that you do NOT expose protocol buffer objects in your library's
+public interface, and that you statically link protocol buffers into your
+library.
+
+TODO(kenton): This sounds kind of scary. Maybe we should only provide static
+ libraries?
+
+Notes on Compiler Warnings
+==========================
+
+The following warnings have been disabled while building the protobuf libraries
+and compiler. You may have to disable some of them in your own project as
+well, or live with them.
+
+C4018 - 'expression' : signed/unsigned mismatch
+C4146 - unary minus operator applied to unsigned type, result still unsigned
+C4244 - Conversion from 'type1' to 'type2', possible loss of data.
+C4251 - 'identifier' : class 'type' needs to have dll-interface to be used by
+ clients of class 'type2'
+C4267 - Conversion from 'size_t' to 'type', possible loss of data.
+C4305 - 'identifier' : truncation from 'type1' to 'type2'
+C4355 - 'this' : used in base member initializer list
+C4800 - 'type' : forcing value to bool 'true' or 'false' (performance warning)
+C4996 - 'function': was declared deprecated
+
+C4251 is of particular note. The protocol buffer library uses templates in
+its public interfaces. MSVC does not provide any reasonable way to export
+template classes from a DLL. However, in practice, it appears that exporting
+templates is not necessary anyway. Since the complete definition of any
+template is available in the header files, anyone importing the DLL will just
+end up compiling instances of the templates into their own binary. The
+Protocol Buffer implementation does not rely on static template members being
+unique, so there should be no problem with this, but MSVC prints warning
+nevertheless. So, we disable it. Unfortunately, this warning will also be
+produced when compiling code which merely uses protocol buffers, meaning you
+may have to disable it in your code too.
diff --git a/vsprojects/tests.vcproj b/vsprojects/tests.vcproj
new file mode 100644
index 00000000..9530557b
--- /dev/null
+++ b/vsprojects/tests.vcproj
@@ -0,0 +1,569 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tests"
+ ProjectGUID="{4DF72760-C055-40A5-A77E-30A17E2AC2DB}"
+ RootNamespace="tests"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ Description=""
+ CommandLine=""
+ AdditionalDependencies=""
+ Outputs=""
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ Description=""
+ CommandLine=""
+ AdditionalDependencies=""
+ Outputs=""
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
+ AdditionalIncludeDirectories="../src;."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\googletest.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\internal\gtest-death-test-internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-death-test.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\internal\gtest-filepath.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-internal-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\internal\gtest-internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\internal\gtest-port.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-spi.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\internal\gtest-string.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest_pred_impl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest_prod.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\test_util.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest.pb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import.pb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_mset.pb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_optimize_for.pb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\google\protobuf\stubs\common_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\stubs\strutil_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\coded_stream_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\command_line_interface_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_bootstrap_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor_database_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\descriptor_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\dynamic_message_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\extension_set_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\file.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\generated_message_reflection_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\testing\googletest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-death-test.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-filepath.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest-port.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest\gtest_main.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\importer_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\message_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\parser_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\printer_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\reflection_ops_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\repeated_field_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\test_util.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\text_format_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\tokenizer_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_import.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_mset.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_optimize_for.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unknown_field_set_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\wire_format_unittest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\io\zero_copy_stream_unittest.cc"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\src\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_import.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_import.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_mset.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_mset.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_mset.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_optimize_for.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_optimize_for.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_optimize_for.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\google\protobuf\unittest_embed_optimize_for.proto"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
+ CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
+ CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
+ Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
+ />
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>