Browse Source

Initial checkin.

temporal 17 years ago
commit
40ee551715
100 changed files with 28976 additions and 0 deletions
  1. 3 0
      CHANGES.txt
  2. 35 0
      CONTRIBUTORS.txt
  3. 202 0
      COPYING.txt
  4. 237 0
      INSTALL.txt
  5. 117 0
      Makefile.am
  6. 57 0
      README.txt
  7. 27 0
      autogen.sh
  8. 34 0
      configure.ac
  9. 5 0
      editors/README.txt
  10. 83 0
      editors/proto.vim
  11. 89 0
      examples/AddPerson.java
  12. 50 0
      examples/ListPeople.java
  13. 56 0
      examples/Makefile
  14. 25 0
      examples/README.txt
  15. 92 0
      examples/add_person.cc
  16. 58 0
      examples/add_person.py
  17. 30 0
      examples/addressbook.proto
  18. 65 0
      examples/list_people.cc
  19. 38 0
      examples/list_people.py
  20. 35 0
      generate_descriptor_proto.sh
  21. 46 0
      java/README.txt
  22. 107 0
      java/pom.xml
  23. 343 0
      java/src/main/java/com/google/protobuf/AbstractMessage.java
  24. 318 0
      java/src/main/java/com/google/protobuf/ByteString.java
  25. 766 0
      java/src/main/java/com/google/protobuf/CodedInputStream.java
  26. 775 0
      java/src/main/java/com/google/protobuf/CodedOutputStream.java
  27. 1635 0
      java/src/main/java/com/google/protobuf/Descriptors.java
  28. 391 0
      java/src/main/java/com/google/protobuf/DynamicMessage.java
  29. 237 0
      java/src/main/java/com/google/protobuf/ExtensionRegistry.java
  30. 662 0
      java/src/main/java/com/google/protobuf/FieldSet.java
  31. 1219 0
      java/src/main/java/com/google/protobuf/GeneratedMessage.java
  32. 77 0
      java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  33. 415 0
      java/src/main/java/com/google/protobuf/Message.java
  34. 27 0
      java/src/main/java/com/google/protobuf/RpcCallback.java
  35. 51 0
      java/src/main/java/com/google/protobuf/RpcChannel.java
  36. 98 0
      java/src/main/java/com/google/protobuf/RpcController.java
  37. 118 0
      java/src/main/java/com/google/protobuf/RpcUtil.java
  38. 97 0
      java/src/main/java/com/google/protobuf/Service.java
  39. 1242 0
      java/src/main/java/com/google/protobuf/TextFormat.java
  40. 146 0
      java/src/main/java/com/google/protobuf/UninitializedMessageException.java
  41. 746 0
      java/src/main/java/com/google/protobuf/UnknownFieldSet.java
  42. 99 0
      java/src/main/java/com/google/protobuf/WireFormat.java
  43. 362 0
      java/src/test/java/com/google/protobuf/AbstractMessageTest.java
  44. 401 0
      java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  45. 280 0
      java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  46. 313 0
      java/src/test/java/com/google/protobuf/DescriptorsTest.java
  47. 120 0
      java/src/test/java/com/google/protobuf/DynamicMessageTest.java
  48. 246 0
      java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  49. 299 0
      java/src/test/java/com/google/protobuf/MessageTest.java
  50. 164 0
      java/src/test/java/com/google/protobuf/ServiceTest.java
  51. 2402 0
      java/src/test/java/com/google/protobuf/TestUtil.java
  52. 534 0
      java/src/test/java/com/google/protobuf/TextFormatTest.java
  53. 315 0
      java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  54. 226 0
      java/src/test/java/com/google/protobuf/WireFormatTest.java
  55. 53 0
      java/src/test/java/com/google/protobuf/multiple_files_test.proto
  56. 363 0
      m4/acx_pthread.m4
  57. 43 0
      m4/stl_hash.m4
  58. 53 0
      python/README.txt
  59. 277 0
      python/ez_setup.py
  60. 1 0
      python/google/__init__.py
  61. 0 0
      python/google/protobuf/__init__.py
  62. 419 0
      python/google/protobuf/descriptor.py
  63. 0 0
      python/google/protobuf/internal/__init__.py
  64. 194 0
      python/google/protobuf/internal/decoder.py
  65. 230 0
      python/google/protobuf/internal/decoder_test.py
  66. 97 0
      python/google/protobuf/internal/descriptor_test.py
  67. 192 0
      python/google/protobuf/internal/encoder.py
  68. 211 0
      python/google/protobuf/internal/encoder_test.py
  69. 84 0
      python/google/protobuf/internal/generator_test.py
  70. 211 0
      python/google/protobuf/internal/input_stream.py
  71. 279 0
      python/google/protobuf/internal/input_stream_test.py
  72. 55 0
      python/google/protobuf/internal/message_listener.py
  73. 44 0
      python/google/protobuf/internal/more_extensions.proto
  74. 37 0
      python/google/protobuf/internal/more_messages.proto
  75. 112 0
      python/google/protobuf/internal/output_stream.py
  76. 162 0
      python/google/protobuf/internal/output_stream_test.py
  77. 1300 0
      python/google/protobuf/internal/reflection_test.py
  78. 98 0
      python/google/protobuf/internal/service_reflection_test.py
  79. 354 0
      python/google/protobuf/internal/test_util.py
  80. 97 0
      python/google/protobuf/internal/text_format_test.py
  81. 222 0
      python/google/protobuf/internal/wire_format.py
  82. 232 0
      python/google/protobuf/internal/wire_format_test.py
  83. 184 0
      python/google/protobuf/message.py
  84. 1734 0
      python/google/protobuf/reflection.py
  85. 194 0
      python/google/protobuf/service.py
  86. 275 0
      python/google/protobuf/service_reflection.py
  87. 111 0
      python/google/protobuf/text_format.py
  88. 1401 0
      python/mox.py
  89. 126 0
      python/setup.py
  90. 140 0
      python/stubout.py
  91. 255 0
      src/Makefile.am
  92. 32 0
      src/google/protobuf/compiler/code_generator.cc
  93. 98 0
      src/google/protobuf/compiler/code_generator.h
  94. 579 0
      src/google/protobuf/compiler/command_line_interface.cc
  95. 210 0
      src/google/protobuf/compiler/command_line_interface.h
  96. 964 0
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  97. 135 0
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  98. 196 0
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  99. 81 0
      src/google/protobuf/compiler/cpp/cpp_enum.h
  100. 226 0
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc

+ 3 - 0
CHANGES.txt

@@ -0,0 +1,3 @@
+2008-07-07 version 2.0.0:
+
+  * First public release.

+ 35 - 0
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>

+ 202 - 0
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.

+ 237 - 0
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.
+

+ 117 - 0
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

+ 57 - 0
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/

+ 27 - 0
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

+ 34 - 0
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 )

+ 5 - 0
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.

+ 83 - 0
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"

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

+ 50 - 0
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);
+  }
+}

+ 56 - 0
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

+ 25 - 0
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

+ 92 - 0
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;
+}

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

+ 30 - 0
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;
+}

+ 65 - 0
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;
+}

+ 38 - 0
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)

+ 35 - 0
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

+ 46 - 0
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/

+ 107 - 0
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>

+ 343 - 0
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;
+    }
+  }
+}

+ 318 - 0
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;
+    }
+  }
+}

+ 766 - 0
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;
+      }
+    }
+  }
+}

+ 775 - 0
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);
+  }
+}

+ 1635 - 0
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.");
+        }
+      }
+    }
+  }
+}

+ 391 - 0
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.");
+      }
+    }
+  }
+}

+ 237 - 0
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;
+    }
+  }
+}

+ 662 - 0
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;
+  }
+}

+ 1219 - 0
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);
+      }
+    }
+  }
+}

+ 77 - 0
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.");
+  }
+}

+ 415 - 0
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;
+  }
+}

+ 27 - 0
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);
+}

+ 51 - 0
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);
+}

+ 98 - 0
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);
+}

+ 118 - 0
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.");
+    }
+  }
+}

+ 97 - 0
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);
+}

+ 1242 - 0
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;
+  }
+}

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

+ 746 - 0
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;
+      }
+    }
+  }
+}

+ 99 - 0
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);
+}

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

+ 401 - 0
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));
+  }
+}

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

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

+ 120 - 0
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);
+  }
+}

+ 246 - 0
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));
+  }
+}

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

+ 164 - 0
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)");
+    }
+  }
+}

+ 2402 - 0
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;
+}

+ 534 - 0
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
+    }
+  }
+}

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

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

+ 53 - 0
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;
+}

+ 363 - 0
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

+ 43 - 0
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
+])

+ 53 - 0
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/

+ 277 - 0
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:])
+
+
+
+
+

+ 1 - 0
python/google/__init__.py

@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)

+ 0 - 0
python/google/protobuf/__init__.py


+ 419 - 0
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;

+ 0 - 0
python/google/protobuf/internal/__init__.py


+ 194 - 0
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.

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

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

+ 192 - 0
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))

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

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

+ 211 - 0
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

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

+ 55 - 0
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

+ 44 - 0
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;
+}

+ 37 - 0
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;
+}

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

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

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

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

+ 354 - 0
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.')

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

+ 222 - 0
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

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

+ 184 - 0
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

+ 1734 - 0
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,
+    }

+ 194 - 0
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

+ 275 - 0
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)

+ 111 - 0
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])

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

+ 126 - 0
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.",
+        )

+ 140 - 0
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 = []

+ 255 - 0
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

+ 32 - 0
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

+ 98 - 0
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__

+ 579 - 0
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

+ 210 - 0
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__

+ 964 - 0
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

+ 135 - 0
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

+ 196 - 0
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

+ 81 - 0
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__

+ 226 - 0
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

Some files were not shown because too many files changed in this diff