Просмотр исходного кода

Submit recent changes from internal branch, including "lite mode" for
C++ and Java. See CHANGES.txt for more details.

kenton@google.com 16 лет назад
Родитель
Сommit
80b1d62bfc
100 измененных файлов с 9918 добавлено и 4337 удалено
  1. 25 1
      CHANGES.txt
  2. 7 0
      Makefile.am
  3. 5 1
      generate_descriptor_proto.sh
  4. 3 0
      java/pom.xml
  5. 457 224
      java/src/main/java/com/google/protobuf/AbstractMessage.java
  6. 321 0
      java/src/main/java/com/google/protobuf/AbstractMessageLite.java
  7. 39 37
      java/src/main/java/com/google/protobuf/ByteString.java
  8. 95 129
      java/src/main/java/com/google/protobuf/CodedInputStream.java
  9. 174 240
      java/src/main/java/com/google/protobuf/CodedOutputStream.java
  10. 246 184
      java/src/main/java/com/google/protobuf/Descriptors.java
  11. 52 29
      java/src/main/java/com/google/protobuf/DynamicMessage.java
  12. 45 35
      java/src/main/java/com/google/protobuf/ExtensionRegistry.java
  13. 169 0
      java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
  14. 449 461
      java/src/main/java/com/google/protobuf/FieldSet.java
  15. 249 224
      java/src/main/java/com/google/protobuf/GeneratedMessage.java
  16. 539 0
      java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  17. 194 0
      java/src/main/java/com/google/protobuf/Internal.java
  18. 3 1
      java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  19. 31 216
      java/src/main/java/com/google/protobuf/Message.java
  20. 331 0
      java/src/main/java/com/google/protobuf/MessageLite.java
  21. 1 1
      java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
  22. 8 5
      java/src/main/java/com/google/protobuf/RpcUtil.java
  23. 4 2
      java/src/main/java/com/google/protobuf/ServiceException.java
  24. 164 132
      java/src/main/java/com/google/protobuf/TextFormat.java
  25. 12 73
      java/src/main/java/com/google/protobuf/UninitializedMessageException.java
  26. 274 115
      java/src/main/java/com/google/protobuf/UnknownFieldSet.java
  27. 62 32
      java/src/main/java/com/google/protobuf/WireFormat.java
  28. 30 0
      java/src/test/java/com/google/protobuf/DescriptorsTest.java
  29. 12 0
      java/src/test/java/com/google/protobuf/DynamicMessageTest.java
  30. 89 0
      java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  31. 114 0
      java/src/test/java/com/google/protobuf/LiteTest.java
  32. 945 86
      java/src/test/java/com/google/protobuf/TestUtil.java
  33. 22 3
      java/src/test/java/com/google/protobuf/TextFormatTest.java
  34. 65 0
      java/src/test/java/com/google/protobuf/WireFormatTest.java
  35. 6 2
      python/google/protobuf/internal/containers.py
  36. 2 2
      python/google/protobuf/internal/decoder.py
  37. 11 7
      python/google/protobuf/internal/decoder_test.py
  38. 4 2
      python/google/protobuf/internal/encoder.py
  39. 8 4
      python/google/protobuf/internal/encoder_test.py
  40. 53 0
      python/google/protobuf/internal/message_test.py
  41. 84 4
      python/google/protobuf/internal/reflection_test.py
  42. 197 1
      python/google/protobuf/internal/test_util.py
  43. 278 3
      python/google/protobuf/internal/text_format_test.py
  44. 4 2
      python/google/protobuf/internal/type_checkers.py
  45. 2 0
      python/google/protobuf/internal/wire_format.py
  46. 1 2
      python/google/protobuf/message.py
  47. 56 10
      python/google/protobuf/reflection.py
  48. 3 2
      python/google/protobuf/service.py
  49. 526 1
      python/google/protobuf/text_format.py
  50. 34 3
      src/Makefile.am
  51. 22 0
      src/google/protobuf/compiler/code_generator.cc
  52. 11 0
      src/google/protobuf/compiler/code_generator.h
  53. 51 28
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  54. 4 0
      src/google/protobuf/compiler/cpp/cpp_enum.h
  55. 52 55
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc
  56. 1 0
      src/google/protobuf/compiler/cpp/cpp_extension.cc
  57. 19 0
      src/google/protobuf/compiler/cpp/cpp_field.cc
  58. 10 0
      src/google/protobuf/compiler/cpp/cpp_field.h
  59. 183 132
      src/google/protobuf/compiler/cpp/cpp_file.cc
  60. 1 28
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  61. 12 1
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  62. 29 0
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  63. 335 188
      src/google/protobuf/compiler/cpp/cpp_message.cc
  64. 4 5
      src/google/protobuf/compiler/cpp/cpp_message.h
  65. 29 38
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  66. 50 61
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  67. 1 1
      src/google/protobuf/compiler/cpp/cpp_service.cc
  68. 84 45
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  69. 50 14
      src/google/protobuf/compiler/cpp/cpp_unittest.cc
  70. 84 64
      src/google/protobuf/compiler/java/java_enum.cc
  71. 26 17
      src/google/protobuf/compiler/java/java_enum_field.cc
  72. 85 14
      src/google/protobuf/compiler/java/java_extension.cc
  73. 38 5
      src/google/protobuf/compiler/java/java_file.cc
  74. 2 0
      src/google/protobuf/compiler/java/java_file.h
  75. 1 27
      src/google/protobuf/compiler/java/java_generator.cc
  76. 67 0
      src/google/protobuf/compiler/java/java_helpers.cc
  77. 30 0
      src/google/protobuf/compiler/java/java_helpers.h
  78. 300 178
      src/google/protobuf/compiler/java/java_message.cc
  79. 22 81
      src/google/protobuf/compiler/java/java_primitive_field.cc
  80. 1 1
      src/google/protobuf/compiler/parser.cc
  81. 66 14
      src/google/protobuf/descriptor.cc
  82. 284 196
      src/google/protobuf/descriptor.pb.cc
  83. 125 72
      src/google/protobuf/descriptor.pb.h
  84. 9 2
      src/google/protobuf/descriptor.proto
  85. 145 0
      src/google/protobuf/descriptor_unittest.cc
  86. 43 41
      src/google/protobuf/dynamic_message.cc
  87. 361 232
      src/google/protobuf/extension_set.cc
  88. 97 47
      src/google/protobuf/extension_set.h
  89. 218 0
      src/google/protobuf/extension_set_heavy.cc
  90. 243 58
      src/google/protobuf/generated_message_reflection.cc
  91. 10 12
      src/google/protobuf/generated_message_reflection.h
  92. 44 0
      src/google/protobuf/generated_message_util.cc
  93. 65 0
      src/google/protobuf/generated_message_util.h
  94. 46 50
      src/google/protobuf/io/coded_stream.cc
  95. 46 0
      src/google/protobuf/io/coded_stream.h
  96. 3 4
      src/google/protobuf/io/gzip_stream.cc
  97. 2 4
      src/google/protobuf/io/gzip_stream.h
  98. 1 1
      src/google/protobuf/io/tokenizer.cc
  99. 1 0
      src/google/protobuf/io/tokenizer_unittest.cc
  100. 0 345
      src/google/protobuf/io/zero_copy_stream_impl.cc

+ 25 - 1
CHANGES.txt

@@ -1,6 +1,9 @@
-????-??-?? version 2.1.1:
+????-??-?? version 2.2.0:
 
   C++
+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler
+    to generate code which only depends libprotobuf-lite, which is much smaller
+    than libprotobuf but lacks descriptors, reflection, and some other features.
   * Fixed bug where Message.Swap(Message) was only implemented for
     optimize_for_speed.  Swap now properly implemented in both modes
     (Issue 91).
@@ -10,6 +13,27 @@
   * Floating-point literals in generated code that are intended to be
     single-precision now explicitly have 'f' suffix to avoid pedantic warnings
     produced by some compilers.
+  * The [deprecated=true] option now causes the C++ code generator to generate
+    a GCC-style deprecation annotation (no-op on other compilers).
+  * google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the
+    EnumDescriptor for that type -- useful for templates which cannot call
+    SomeGeneratedEnumType_descriptor().
+  * Various optimizations and obscure bug fixes.
+
+  Java
+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler
+    to generate code which only depends libprotobuf-lite, which is much smaller
+    than libprotobuf but lacks descriptors, reflection, and some other features.
+  * Put Builder objects on a freelist after build() is called, so they may be
+    reused later.
+  * Lots of style cleanups.
+
+  Python
+  * Fixed endianness bug with floats and doubles.
+  * Text format parsing support.
+  * Fix bug with parsing packed repeated fields in embedded messages.
+  * Ability to initialize fields by passing keyword args to constructor.
+  * Support iterators in extend and __setslice__ for containers.
 
 2009-05-13 version 2.1.0:
 

+ 7 - 0
Makefile.am

@@ -62,6 +62,7 @@ EXTRA_DIST =                                                                 \
   examples/add_person.py                                                     \
   examples/list_people.py                                                    \
   java/src/main/java/com/google/protobuf/AbstractMessage.java                \
+  java/src/main/java/com/google/protobuf/AbstractMessageLite.java            \
   java/src/main/java/com/google/protobuf/BlockingRpcChannel.java             \
   java/src/main/java/com/google/protobuf/BlockingService.java                \
   java/src/main/java/com/google/protobuf/ByteString.java                     \
@@ -70,10 +71,14 @@ EXTRA_DIST =                                                                 \
   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/ExtensionRegistryLite.java          \
   java/src/main/java/com/google/protobuf/FieldSet.java                       \
   java/src/main/java/com/google/protobuf/GeneratedMessage.java               \
+  java/src/main/java/com/google/protobuf/GeneratedMessageLite.java           \
+  java/src/main/java/com/google/protobuf/Internal.java                       \
   java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
   java/src/main/java/com/google/protobuf/Message.java                        \
+  java/src/main/java/com/google/protobuf/MessageLite.java                    \
   java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java            \
   java/src/main/java/com/google/protobuf/RpcCallback.java                    \
   java/src/main/java/com/google/protobuf/RpcChannel.java                     \
@@ -91,6 +96,7 @@ EXTRA_DIST =                                                                 \
   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/LiteTest.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                       \
@@ -110,6 +116,7 @@ EXTRA_DIST =                                                                 \
   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/message_test.py                            \
   python/google/protobuf/internal/more_extensions.proto                      \
   python/google/protobuf/internal/more_messages.proto                        \
   python/google/protobuf/internal/output_stream.py                           \

+ 5 - 1
generate_descriptor_proto.sh

@@ -5,6 +5,10 @@
 # itself, they cannot be generated automatically by a make rule.  "make check"
 # will fail if these files do not match what the protocol compiler would
 # generate.
+#
+# HINT:  Flags passed to generate_descriptor_proto.sh will be passed directly
+#   to make when building protoc.  This is particularly useful for passing
+#   -j4 to run 4 jobs simultaneously.
 
 if test ! -e src/google/protobuf/stubs/common.h; then
   cat >&2 << __EOF__
@@ -23,5 +27,5 @@ __EOF__
 fi
 
 cd src
-make protoc && ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto
+make $@ protoc && ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto
 cd ..

+ 3 - 0
java/pom.xml

@@ -124,6 +124,9 @@
                     value="../src/google/protobuf/unittest_optimize_for.proto" />
                   <arg
                     value="../src/google/protobuf/unittest_custom_options.proto" />
+                  <arg value="../src/google/protobuf/unittest_lite.proto" />
+                  <arg value="../src/google/protobuf/unittest_import_lite.proto" />
+                  <arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
                 </exec>
               </tasks>
               <testSourceRoot>target/generated-test-sources</testSourceRoot>

+ 457 - 224
java/src/main/java/com/google/protobuf/AbstractMessage.java

@@ -30,12 +30,12 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 
-import java.io.FilterInputStream;
 import java.io.InputStream;
 import java.io.IOException;
-import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -45,11 +45,12 @@ import java.util.Map;
  *
  * @author kenton@google.com Kenton Varda
  */
-public abstract class AbstractMessage implements Message {
+public abstract class AbstractMessage extends AbstractMessageLite
+                                      implements Message {
   @SuppressWarnings("unchecked")
   public boolean isInitialized() {
     // Check that all required fields are present.
-    for (FieldDescriptor field : getDescriptorForType().getFields()) {
+    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
       if (field.isRequired()) {
         if (!hasField(field)) {
           return false;
@@ -58,11 +59,12 @@ public abstract class AbstractMessage implements Message {
     }
 
     // Check that embedded messages are initialized.
-    for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
-      FieldDescriptor field = entry.getKey();
+    for (final Map.Entry<FieldDescriptor, Object> entry :
+        getAllFields().entrySet()) {
+      final FieldDescriptor field = entry.getKey();
       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
         if (field.isRepeated()) {
-          for (Message element : (List<Message>) entry.getValue()) {
+          for (final Message element : (List<Message>) entry.getValue()) {
             if (!element.isInitialized()) {
               return false;
             }
@@ -83,117 +85,59 @@ public abstract class AbstractMessage implements Message {
     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()) {
-        List valueList = (List) entry.getValue();
-        if (field.getOptions().getPacked()) {
-
-          output.writeTag(field.getNumber(),
-                          WireFormat.WIRETYPE_LENGTH_DELIMITED);
-          int dataSize = 0;
-          for (Object element : valueList) {
-            dataSize += CodedOutputStream.computeFieldSizeNoTag(
-                field.getType(), element);
-          }
-          output.writeRawVarint32(dataSize);
-
-          for (Object element : valueList) {
-            output.writeFieldNoTag(field.getType(), element);
-          }
-        } else {
-          for (Object element : valueList) {
-            output.writeField(field.getType(), field.getNumber(), element);
-          }
-        }
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    final boolean isMessageSet =
+        getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+    for (final Map.Entry<FieldDescriptor, Object> entry :
+        getAllFields().entrySet()) {
+      final FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        output.writeMessageSetExtension(field.getNumber(), (Message) value);
       } else {
-        output.writeField(field.getType(), field.getNumber(), entry.getValue());
+        FieldSet.writeField(field, value, output);
       }
     }
 
-    UnknownFieldSet unknownFields = getUnknownFields();
-    if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
+    final UnknownFieldSet unknownFields = getUnknownFields();
+    if (isMessageSet) {
       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();
-  }
-
-  public void writeDelimitedTo(OutputStream output) throws IOException {
-    CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
-    codedOutput.writeRawVarint32(getSerializedSize());
-    writeTo(codedOutput);
-    codedOutput.flush();
-  }
-
   private int memoizedSize = -1;
 
   public int getSerializedSize() {
     int size = memoizedSize;
-    if (size != -1) return size;
+    if (size != -1) {
+      return size;
+    }
 
     size = 0;
-    for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
-      FieldDescriptor field = entry.getKey();
-      if (field.isRepeated()) {
-        List valueList = (List) entry.getValue();
-        if (field.getOptions().getPacked()) {
-          int dataSize = 0;
-          for (Object element : valueList) {
-            dataSize += CodedOutputStream.computeFieldSizeNoTag(
-                field.getType(), element);
-          }
-          size += dataSize;
-          size += CodedOutputStream.computeTagSize(field.getNumber());
-          size += CodedOutputStream.computeRawVarint32Size(dataSize);
-        } else {
-          for (Object element : valueList) {
-            size += CodedOutputStream.computeFieldSize(
-                field.getType(), field.getNumber(), element);
-          }
-        }
+    final boolean isMessageSet =
+        getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+    for (final Map.Entry<FieldDescriptor, Object> entry :
+        getAllFields().entrySet()) {
+      final FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        size += CodedOutputStream.computeMessageSetExtensionSize(
+            field.getNumber(), (Message) value);
       } else {
-        size += CodedOutputStream.computeFieldSize(
-          field.getType(), field.getNumber(), entry.getValue());
+        size += FieldSet.computeFieldSize(field, value);
       }
     }
 
-    UnknownFieldSet unknownFields = getUnknownFields();
-    if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
+    final UnknownFieldSet unknownFields = getUnknownFields();
+    if (isMessageSet) {
       size += unknownFields.getSerializedSizeAsMessageSet();
     } else {
       size += unknownFields.getSerializedSize();
@@ -204,14 +148,14 @@ public abstract class AbstractMessage implements Message {
   }
 
   @Override
-  public boolean equals(Object other) {
+  public boolean equals(final Object other) {
     if (other == this) {
       return true;
     }
     if (!(other instanceof Message)) {
       return false;
     }
-    Message otherMessage = (Message) other;
+    final Message otherMessage = (Message) other;
     if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
       return false;
     }
@@ -237,20 +181,21 @@ public abstract class AbstractMessage implements Message {
    */
   @SuppressWarnings("unchecked")
   public static abstract class Builder<BuilderType extends Builder>
+      extends AbstractMessageLite.Builder<BuilderType>
       implements Message.Builder {
     // The compiler produces an error if this is not declared explicitly.
     @Override
     public abstract BuilderType clone();
 
     public BuilderType clear() {
-      for (Map.Entry<FieldDescriptor, Object> entry :
+      for (final Map.Entry<FieldDescriptor, Object> entry :
            getAllFields().entrySet()) {
         clearField(entry.getKey());
       }
       return (BuilderType) this;
     }
 
-    public BuilderType mergeFrom(Message other) {
+    public BuilderType mergeFrom(final Message other) {
       if (other.getDescriptorForType() != getDescriptorForType()) {
         throw new IllegalArgumentException(
           "mergeFrom(Message) can only merge messages of the same type.");
@@ -265,15 +210,15 @@ public abstract class AbstractMessage implements Message {
       // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
       //   which allows people to make secure deep copies of messages.
 
-      for (Map.Entry<FieldDescriptor, Object> entry :
+      for (final Map.Entry<FieldDescriptor, Object> entry :
            other.getAllFields().entrySet()) {
-        FieldDescriptor field = entry.getKey();
+        final FieldDescriptor field = entry.getKey();
         if (field.isRepeated()) {
-          for (Object element : (List)entry.getValue()) {
+          for (final Object element : (List)entry.getValue()) {
             addRepeatedField(field, element);
           }
         } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-          Message existingValue = (Message)getField(field);
+          final Message existingValue = (Message)getField(field);
           if (existingValue == existingValue.getDefaultInstanceForType()) {
             setField(field, entry.getValue());
           } else {
@@ -288,24 +233,288 @@ public abstract class AbstractMessage implements Message {
         }
       }
 
+      mergeUnknownFields(other.getUnknownFields());
+
       return (BuilderType) this;
     }
 
-    public BuilderType mergeFrom(CodedInputStream input) throws IOException {
+    @Override
+    public BuilderType mergeFrom(final CodedInputStream input)
+                                 throws IOException {
       return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
     }
 
-    public BuilderType mergeFrom(CodedInputStream input,
-                                 ExtensionRegistry extensionRegistry)
-                                 throws IOException {
-      UnknownFieldSet.Builder unknownFields =
+    @Override
+    public BuilderType mergeFrom(
+        final CodedInputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final UnknownFieldSet.Builder unknownFields =
         UnknownFieldSet.newBuilder(getUnknownFields());
-      FieldSet.mergeFrom(input, unknownFields, extensionRegistry, this);
+      while (true) {
+        final int tag = input.readTag();
+        if (tag == 0) {
+          break;
+        }
+
+        if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
+                            this, tag)) {
+          // end group tag
+          break;
+        }
+      }
       setUnknownFields(unknownFields.build());
       return (BuilderType) this;
     }
 
-    public BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) {
+    /**
+     * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
+     * ExtensionRegistryLite, Message.Builder)}, but parses a single field.
+     * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+     * @param tag The tag, which should have already been read.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    @SuppressWarnings("unchecked")
+    static boolean mergeFieldFrom(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final Message.Builder builder,
+        final int tag) throws IOException {
+      final Descriptor type = builder.getDescriptorForType();
+
+      if (type.getOptions().getMessageSetWireFormat() &&
+          tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+        mergeMessageSetExtensionFromCodedStream(
+          input, unknownFields, extensionRegistry, builder);
+        return true;
+      }
+
+      final int wireType = WireFormat.getTagWireType(tag);
+      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+      final FieldDescriptor field;
+      Message defaultInstance = null;
+
+      if (type.isExtensionNumber(fieldNumber)) {
+        // extensionRegistry may be either ExtensionRegistry or
+        // ExtensionRegistryLite.  Since the type we are parsing is a full
+        // message, only a full ExtensionRegistry could possibly contain
+        // extensions of it.  Otherwise we will treat the registry as if it
+        // were empty.
+        if (extensionRegistry instanceof ExtensionRegistry) {
+          final ExtensionRegistry.ExtensionInfo extension =
+            ((ExtensionRegistry) extensionRegistry)
+              .findExtensionByNumber(type, fieldNumber);
+          if (extension == null) {
+            field = null;
+          } else {
+            field = extension.descriptor;
+            defaultInstance = extension.defaultInstance;
+          }
+        } else {
+          field = null;
+        }
+      } else {
+        field = type.findFieldByNumber(fieldNumber);
+      }
+
+      if (field == null || wireType !=
+            FieldSet.getWireFormatForFieldType(
+                field.getLiteType(),
+                field.getOptions().getPacked())) {
+        // Unknown field or wrong wire type.  Skip.
+        return unknownFields.mergeFieldFrom(tag, input);
+      }
+
+      if (field.getOptions().getPacked()) {
+        final int length = input.readRawVarint32();
+        final int limit = input.pushLimit(length);
+        if (field.getLiteType() == WireFormat.FieldType.ENUM) {
+          while (input.getBytesUntilLimit() > 0) {
+            final int rawValue = input.readEnum();
+            final Object value = field.getEnumType().findValueByNumber(rawValue);
+            if (value == null) {
+              // If the number isn't recognized as a valid value for this
+              // enum, drop it (don't even add it to unknownFields).
+              return true;
+            }
+            builder.addRepeatedField(field, value);
+          }
+        } else {
+          while (input.getBytesUntilLimit() > 0) {
+            final Object value =
+              FieldSet.readPrimitiveField(input, field.getLiteType());
+            builder.addRepeatedField(field, value);
+          }
+        }
+        input.popLimit(limit);
+      } else {
+        final Object value;
+        switch (field.getType()) {
+          case GROUP: {
+            final 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: {
+            final 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:
+            final int rawValue = input.readEnum();
+            value = field.getEnumType().findValueByNumber(rawValue);
+            // If the number isn't recognized as a valid value for this enum,
+            // drop it.
+            if (value == null) {
+              unknownFields.mergeVarintField(fieldNumber, rawValue);
+              return true;
+            }
+            break;
+          default:
+            value = FieldSet.readPrimitiveField(input, field.getLiteType());
+            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(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final Message.Builder builder) throws IOException {
+      final 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) {
+        final 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) {
+            final ExtensionRegistry.ExtensionInfo extension;
+
+            // extensionRegistry may be either ExtensionRegistry or
+            // ExtensionRegistryLite.  Since the type we are parsing is a full
+            // message, only a full ExtensionRegistry could possibly contain
+            // extensions of it.  Otherwise we will treat the registry as if it
+            // were empty.
+            if (extensionRegistry instanceof ExtensionRegistry) {
+              extension = ((ExtensionRegistry) extensionRegistry)
+                  .findExtensionByNumber(type, typeId);
+            } else {
+              extension = null;
+            }
+
+            if (extension != null) {
+              field = extension.descriptor;
+              subBuilder = extension.defaultInstance.newBuilderForType();
+              final 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());
+      }
+    }
+
+    public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
       setUnknownFields(
         UnknownFieldSet.newBuilder(getUnknownFields())
                        .mergeFrom(unknownFields)
@@ -313,145 +522,169 @@ public abstract class AbstractMessage implements Message {
       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);
+    /**
+     * Construct an UninitializedMessageException reporting missing fields in
+     * the given message.
+     */
+    protected static UninitializedMessageException
+        newUninitializedMessageException(Message message) {
+      return new UninitializedMessageException(findMissingFields(message));
+    }
+
+    /**
+     * Populates {@code this.missingFields} with the full "path" of each
+     * missing required field in the given message.
+     */
+    private static List<String> findMissingFields(final Message message) {
+      final List<String> results = new ArrayList<String>();
+      findMissingFields(message, "", results);
+      return results;
+    }
+
+    /** Recursive helper implementing {@link #findMissingFields(Message)}. */
+    private static void findMissingFields(final Message message,
+                                          final String prefix,
+                                          final List<String> results) {
+      for (final FieldDescriptor field :
+          message.getDescriptorForType().getFields()) {
+        if (field.isRequired() && !message.hasField(field)) {
+          results.add(prefix + field.getName());
+        }
+      }
+
+      for (final Map.Entry<FieldDescriptor, Object> entry :
+           message.getAllFields().entrySet()) {
+        final FieldDescriptor field = entry.getKey();
+        final Object value = entry.getValue();
+
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (field.isRepeated()) {
+            int i = 0;
+            for (final 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);
+            }
+          }
+        }
       }
     }
 
-    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);
+    private static String subMessagePrefix(final String prefix,
+                                           final FieldDescriptor field,
+                                           final int index) {
+      final StringBuilder result = new StringBuilder(prefix);
+      if (field.isExtension()) {
+        result.append('(')
+              .append(field.getFullName())
+              .append(')');
+      } else {
+        result.append(field.getName());
       }
+      if (index != -1) {
+        result.append('[')
+              .append(index)
+              .append(']');
+      }
+      result.append('.');
+      return result.toString();
     }
 
-    public BuilderType mergeFrom(byte[] data)
+    // ===============================================================
+    // The following definitions seem to be required in order to make javac
+    // not produce weird errors like:
+    //
+    // java/com/google/protobuf/DynamicMessage.java:203: types
+    //   com.google.protobuf.AbstractMessage.Builder<
+    //     com.google.protobuf.DynamicMessage.Builder> and
+    //   com.google.protobuf.AbstractMessage.Builder<
+    //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
+    //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
+    //   return types.
+    //
+    // Strangely, these lines are only needed if javac is invoked separately
+    // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
+    // invoked on both simultaneously, it works.  (Or maybe the important
+    // point is whether or not DynamicMessage.java is compiled together with
+    // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
+    // bug.
+
+    @Override
+    public BuilderType mergeFrom(final ByteString data)
         throws InvalidProtocolBufferException {
-      return mergeFrom(data, 0, data.length);
+      return super.mergeFrom(data);
     }
 
-    public BuilderType mergeFrom(byte[] data, int off, int len)
+    @Override
+    public BuilderType mergeFrom(
+        final ByteString data,
+        final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
-      try {
-        CodedInputStream input = CodedInputStream.newInstance(data, off, len);
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
+      return super.mergeFrom(data, extensionRegistry);
     }
 
-    public BuilderType mergeFrom(
-        byte[] data,
-        ExtensionRegistry extensionRegistry)
+    @Override
+    public BuilderType mergeFrom(final byte[] data)
         throws InvalidProtocolBufferException {
-      return mergeFrom(data, 0, data.length, extensionRegistry);
+      return super.mergeFrom(data);
     }
 
+    @Override
     public BuilderType mergeFrom(
-        byte[] data, int off, int len,
-        ExtensionRegistry extensionRegistry)
+        final byte[] data, final int off, final int len)
         throws InvalidProtocolBufferException {
-      try {
-        CodedInputStream input = CodedInputStream.newInstance(data, off, len);
-        mergeFrom(input, extensionRegistry);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
+      return super.mergeFrom(data, off, len);
     }
 
-    public BuilderType mergeFrom(InputStream input) throws IOException {
-      CodedInputStream codedInput = CodedInputStream.newInstance(input);
-      mergeFrom(codedInput);
-      codedInput.checkLastTagWas(0);
-      return (BuilderType) this;
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return super.mergeFrom(data, extensionRegistry);
     }
 
-    public BuilderType mergeFrom(InputStream input,
-                                 ExtensionRegistry extensionRegistry)
-                                 throws IOException {
-      CodedInputStream codedInput = CodedInputStream.newInstance(input);
-      mergeFrom(codedInput, extensionRegistry);
-      codedInput.checkLastTagWas(0);
-      return (BuilderType) this;
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data, final int off, final int len,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return super.mergeFrom(data, off, len, extensionRegistry);
     }
 
-    public BuilderType mergeDelimitedFrom(InputStream input,
-                                          ExtensionRegistry extensionRegistry)
-                                          throws IOException {
-      final int size = CodedInputStream.readRawVarint32(input);
-
-      // A stream which will not read more than |size| bytes.
-      InputStream limitedInput = new FilterInputStream(input) {
-        int limit = size;
-
-        @Override
-        public int available() throws IOException {
-          return Math.min(super.available(), limit);
-        }
-
-        @Override
-        public int read() throws IOException {
-          if (limit <= 0) return -1;
-          int result = super.read();
-          if (result >= 0) --limit;
-          return result;
-        }
+    @Override
+    public BuilderType mergeFrom(final InputStream input)
+        throws IOException {
+      return super.mergeFrom(input);
+    }
 
-        @Override
-        public int read(byte[] b, int off, int len) throws IOException {
-          if (limit <= 0) return -1;
-          len = Math.min(len, limit);
-          int result = super.read(b, off, len);
-          if (result >= 0) limit -= result;
-          return result;
-        }
+    @Override
+    public BuilderType mergeFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      return super.mergeFrom(input, extensionRegistry);
+    }
 
-        @Override
-        public long skip(long n) throws IOException {
-          long result = super.skip(Math.min(n, limit));
-          if (result >= 0) limit -= result;
-          return result;
-        }
-      };
-      return mergeFrom(limitedInput, extensionRegistry);
+    @Override
+    public BuilderType mergeDelimitedFrom(final InputStream input)
+        throws IOException {
+      return super.mergeDelimitedFrom(input);
     }
 
-    public BuilderType mergeDelimitedFrom(InputStream input)
+    @Override
+    public BuilderType mergeDelimitedFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      return mergeDelimitedFrom(input, ExtensionRegistry.getEmptyRegistry());
+      return super.mergeDelimitedFrom(input, extensionRegistry);
     }
+
   }
 }

+ 321 - 0
java/src/main/java/com/google/protobuf/AbstractMessageLite.java

@@ -0,0 +1,321 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+
+/**
+ * A partial implementation of the {@link MessageLite} interface which
+ * implements as many methods of that interface as possible in terms of other
+ * methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessageLite implements MessageLite {
+  public ByteString toByteString() {
+    try {
+      final ByteString.CodedBuilder out =
+        ByteString.newCodedBuilder(getSerializedSize());
+      writeTo(out.getCodedOutput());
+      return out.build();
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Serializing to a ByteString threw an IOException (should " +
+        "never happen).", e);
+    }
+  }
+
+  public byte[] toByteArray() {
+    try {
+      final byte[] result = new byte[getSerializedSize()];
+      final CodedOutputStream output = CodedOutputStream.newInstance(result);
+      writeTo(output);
+      output.checkNoSpaceLeft();
+      return result;
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Serializing to a byte array threw an IOException " +
+        "(should never happen).", e);
+    }
+  }
+
+  public void writeTo(final OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  public void writeDelimitedTo(final OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    codedOutput.writeRawVarint32(getSerializedSize());
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  /**
+   * A partial implementation of the {@link Message.Builder} interface which
+   * implements as many methods of that interface as possible in terms of
+   * other methods.
+   */
+  @SuppressWarnings("unchecked")
+  public static abstract class Builder<BuilderType extends Builder>
+      implements MessageLite.Builder {
+    // The compiler produces an error if this is not declared explicitly.
+    @Override
+    public abstract BuilderType clone();
+
+    public BuilderType mergeFrom(final CodedInputStream input)
+                                 throws IOException {
+      // TODO(kenton):  Don't use null here.  Currently we have to because
+      //   using ExtensionRegistry.getEmptyRegistry() would imply a dependency
+      //   on ExtensionRegistry.  However, AbstractMessage overrides this with
+      //   a correct implementation, and lite messages don't yet support
+      //   extensions, so it ends up not mattering for now.  It will matter
+      //   once lite messages support extensions.
+      return mergeFrom(input, null);
+    }
+
+    // Re-defined here for return type covariance.
+    public abstract BuilderType mergeFrom(
+        final CodedInputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+
+    public BuilderType mergeFrom(final ByteString data)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = data.newCodedInput();
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a ByteString threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    public BuilderType mergeFrom(
+        final ByteString data,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = data.newCodedInput();
+        mergeFrom(input, extensionRegistry);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a ByteString threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    public BuilderType mergeFrom(final byte[] data)
+        throws InvalidProtocolBufferException {
+      return mergeFrom(data, 0, data.length);
+    }
+
+    public BuilderType mergeFrom(final byte[] data, final int off,
+                                 final int len)
+                                 throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    public BuilderType mergeFrom(
+        final byte[] data,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return mergeFrom(data, 0, data.length, extensionRegistry);
+    }
+
+    public BuilderType mergeFrom(
+        final byte[] data, final int off, final int len,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input, extensionRegistry);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    public BuilderType mergeFrom(final InputStream input) throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+      mergeFrom(codedInput);
+      codedInput.checkLastTagWas(0);
+      return (BuilderType) this;
+    }
+
+    public BuilderType mergeFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+      mergeFrom(codedInput, extensionRegistry);
+      codedInput.checkLastTagWas(0);
+      return (BuilderType) this;
+    }
+
+    /**
+     * An InputStream implementations which reads from some other InputStream
+     * but is limited to a particular number of bytes.  Used by
+     * mergeDelimitedFrom().  This is intentionally package-private so that
+     * UnknownFieldSet can share it.
+     */
+    static final class LimitedInputStream extends FilterInputStream {
+      private int limit;
+
+      LimitedInputStream(InputStream in, int limit) {
+        super(in);
+        this.limit = limit;
+      }
+
+      @Override
+      public int available() throws IOException {
+        return Math.min(super.available(), limit);
+      }
+
+      @Override
+      public int read() throws IOException {
+        if (limit <= 0) {
+          return -1;
+        }
+        final int result = super.read();
+        if (result >= 0) {
+          --limit;
+        }
+        return result;
+      }
+
+      @Override
+      public int read(final byte[] b, final int off, int len)
+                      throws IOException {
+        if (limit <= 0) {
+          return -1;
+        }
+        len = Math.min(len, limit);
+        final int result = super.read(b, off, len);
+        if (result >= 0) {
+          limit -= result;
+        }
+        return result;
+      }
+
+      @Override
+      public long skip(final long n) throws IOException {
+        final long result = super.skip(Math.min(n, limit));
+        if (result >= 0) {
+          limit -= result;
+        }
+        return result;
+      }
+    }
+
+    public BuilderType mergeDelimitedFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final int size = CodedInputStream.readRawVarint32(input);
+      final InputStream limitedInput = new LimitedInputStream(input, size);
+      return mergeFrom(limitedInput, extensionRegistry);
+    }
+
+    public BuilderType mergeDelimitedFrom(final InputStream input)
+        throws IOException {
+      final int size = CodedInputStream.readRawVarint32(input);
+      final InputStream limitedInput = new LimitedInputStream(input, size);
+      return mergeFrom(limitedInput);
+    }
+
+    /**
+     * Construct an UninitializedMessageException reporting missing fields in
+     * the given message.
+     */
+    protected static UninitializedMessageException
+        newUninitializedMessageException(MessageLite message) {
+      return new UninitializedMessageException(message);
+    }
+
+    /**
+     * Adds the {@code values} to the {@code list}.  This is a helper method
+     * used by generated code.  Users should ignore it.
+     *
+     * @throws NullPointerException if any of the elements of {@code values} is
+     * null.
+     */
+    protected static <T> void addAll(final Iterable<T> values,
+                                     final Collection<? super T> list) {
+      for (final T value : values) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+      }
+      if (values instanceof Collection) {
+        @SuppressWarnings("unsafe") final
+        Collection<T> collection = (Collection<T>) values;
+        list.addAll(collection);
+      } else {
+        for (final T value : values) {
+          list.add(value);
+        }
+      }
+    }
+  }
+}

+ 39 - 37
java/src/main/java/com/google/protobuf/ByteString.java

@@ -46,7 +46,7 @@ import java.nio.ByteBuffer;
 public final class ByteString {
   private final byte[] bytes;
 
-  private ByteString(byte[] bytes) {
+  private ByteString(final byte[] bytes) {
     this.bytes = bytes;
   }
 
@@ -55,7 +55,7 @@ public final class ByteString {
    *
    * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
    */
-  public byte byteAt(int index) {
+  public byte byteAt(final int index) {
     return bytes[index];
   }
 
@@ -63,14 +63,14 @@ public final class ByteString {
    * Gets the number of bytes.
    */
   public int size() {
-    return this.bytes.length;
+    return bytes.length;
   }
 
   /**
    * Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
    */
   public boolean isEmpty() {
-    return this.bytes.length == 0;
+    return bytes.length == 0;
   }
 
   // =================================================================
@@ -84,8 +84,9 @@ public final class ByteString {
   /**
    * Copies the given bytes into a {@code ByteString}.
    */
-  public static ByteString copyFrom(byte[] bytes, int offset, int size) {
-    byte[] copy = new byte[size];
+  public static ByteString copyFrom(final byte[] bytes, final int offset,
+                                    final int size) {
+    final byte[] copy = new byte[size];
     System.arraycopy(bytes, offset, copy, 0, size);
     return new ByteString(copy);
   }
@@ -93,7 +94,7 @@ public final class ByteString {
   /**
    * Copies the given bytes into a {@code ByteString}.
    */
-  public static ByteString copyFrom(byte[] bytes) {
+  public static ByteString copyFrom(final byte[] bytes) {
     return copyFrom(bytes, 0, bytes.length);
   }
 
@@ -101,7 +102,7 @@ public final class ByteString {
    * 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)
+  public static ByteString copyFrom(final String text, final String charsetName)
       throws UnsupportedEncodingException {
     return new ByteString(text.getBytes(charsetName));
   }
@@ -110,7 +111,7 @@ public final class ByteString {
    * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
    * result as a {@code ByteString}.
    */
-  public static ByteString copyFromUtf8(String text) {
+  public static ByteString copyFromUtf8(final String text) {
     try {
       return new ByteString(text.getBytes("UTF-8"));
     } catch (UnsupportedEncodingException e) {
@@ -127,7 +128,7 @@ public final class ByteString {
    * @param target buffer to copy into
    * @param offset in the target buffer
    */
-  public void copyTo(byte[] target, int offset) {
+  public void copyTo(final byte[] target, final int offset) {
     System.arraycopy(bytes, 0, target, offset, bytes.length);
   }
 
@@ -139,8 +140,9 @@ public final class ByteString {
    * @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) {
+  public void copyTo(final byte[] target, final int sourceOffset,
+                     final int targetOffset,
+      final int size) {
     System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
   }
 
@@ -148,9 +150,9 @@ public final class ByteString {
    * 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);
+    final int size = bytes.length;
+    final byte[] copy = new byte[size];
+    System.arraycopy(bytes, 0, copy, 0, size);
     return copy;
   }
 
@@ -159,7 +161,7 @@ public final class ByteString {
    * same backing byte array.
    */
   public ByteBuffer asReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer = ByteBuffer.wrap(this.bytes);
+    final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
     return byteBuffer.asReadOnlyBuffer();
   }
 
@@ -167,9 +169,9 @@ public final class ByteString {
    * Constructs a new {@code String} by decoding the bytes using the
    * specified charset.
    */
-  public String toString(String charsetName)
+  public String toString(final String charsetName)
       throws UnsupportedEncodingException {
-    return new String(this.bytes, charsetName);
+    return new String(bytes, charsetName);
   }
 
   /**
@@ -177,7 +179,7 @@ public final class ByteString {
    */
   public String toStringUtf8() {
     try {
-      return new String(this.bytes, "UTF-8");
+      return new String(bytes, "UTF-8");
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException("UTF-8 not supported?", e);
     }
@@ -187,7 +189,7 @@ public final class ByteString {
   // equals() and hashCode()
 
   @Override
-  public boolean equals(Object o) {
+  public boolean equals(final Object o) {
     if (o == this) {
       return true;
     }
@@ -196,16 +198,16 @@ public final class ByteString {
       return false;
     }
 
-    ByteString other = (ByteString) o;
-    int size = this.bytes.length;
+    final ByteString other = (ByteString) o;
+    final int size = bytes.length;
     if (size != other.bytes.length) {
       return false;
     }
 
-    byte[] bytes = this.bytes;
-    byte[] otherBytes = other.bytes;
+    final byte[] thisBytes = bytes;
+    final byte[] otherBytes = other.bytes;
     for (int i = 0; i < size; i++) {
-      if (bytes[i] != otherBytes[i]) {
+      if (thisBytes[i] != otherBytes[i]) {
         return false;
       }
     }
@@ -213,25 +215,25 @@ public final class ByteString {
     return true;
   }
 
-  volatile int hash = 0;
+  private volatile int hash = 0;
 
   @Override
   public int hashCode() {
-    int h = this.hash;
+    int h = hash;
 
     if (h == 0) {
-      byte[] bytes = this.bytes;
-      int size = this.bytes.length;
+      final byte[] thisBytes = bytes;
+      final int size = bytes.length;
 
       h = size;
       for (int i = 0; i < size; i++) {
-        h = h * 31 + bytes[i];
+        h = h * 31 + thisBytes[i];
       }
       if (h == 0) {
         h = 1;
       }
 
-      this.hash = h;
+      hash = h;
     }
 
     return h;
@@ -264,7 +266,7 @@ public final class ByteString {
   /**
    * Creates a new {@link Output} with the given initial capacity.
    */
-  public static Output newOutput(int initialCapacity) {
+  public static Output newOutput(final int initialCapacity) {
     return new Output(new ByteArrayOutputStream(initialCapacity));
   }
 
@@ -285,7 +287,7 @@ public final class ByteString {
     /**
      * Constructs a new output with the given initial capacity.
      */
-    private Output(ByteArrayOutputStream bout) {
+    private Output(final ByteArrayOutputStream bout) {
       super(bout);
       this.bout = bout;
     }
@@ -294,14 +296,14 @@ public final class ByteString {
      * Creates a {@code ByteString} instance from this {@code Output}.
      */
     public ByteString toByteString() {
-      byte[] byteArray = bout.toByteArray();
+      final 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}.
+   * construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
    * Using this is much more efficient than calling {@code newOutput()} and
    * wrapping that in a {@code CodedOutputStream}.
    *
@@ -312,7 +314,7 @@ public final class ByteString {
    * @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) {
+  static CodedBuilder newCodedBuilder(final int size) {
     return new CodedBuilder(size);
   }
 
@@ -321,7 +323,7 @@ public final class ByteString {
     private final CodedOutputStream output;
     private final byte[] buffer;
 
-    private CodedBuilder(int size) {
+    private CodedBuilder(final int size) {
       buffer = new byte[size];
       output = CodedOutputStream.newInstance(buffer);
     }

+ 95 - 129
java/src/main/java/com/google/protobuf/CodedInputStream.java

@@ -51,21 +51,22 @@ public final class CodedInputStream {
   /**
    * Create a new CodedInputStream wrapping the given InputStream.
    */
-  public static CodedInputStream newInstance(InputStream input) {
+  public static CodedInputStream newInstance(final InputStream input) {
     return new CodedInputStream(input);
   }
 
   /**
    * Create a new CodedInputStream wrapping the given byte array.
    */
-  public static CodedInputStream newInstance(byte[] buf) {
+  public static CodedInputStream newInstance(final byte[] buf) {
     return newInstance(buf, 0, buf.length);
   }
 
   /**
    * Create a new CodedInputStream wrapping the given byte array slice.
    */
-  public static CodedInputStream newInstance(byte[] buf, int off, int len) {
+  public static CodedInputStream newInstance(final byte[] buf, final int off,
+                                             final int len) {
     return new CodedInputStream(buf, off, len);
   }
 
@@ -98,7 +99,8 @@ public final class CodedInputStream {
    * @throws InvalidProtocolBufferException {@code value} does not match the
    *                                        last tag.
    */
-  public void checkLastTagWas(int value) throws InvalidProtocolBufferException {
+  public void checkLastTagWas(final int value)
+                              throws InvalidProtocolBufferException {
     if (lastTag != value) {
       throw InvalidProtocolBufferException.invalidEndTag();
     }
@@ -110,7 +112,7 @@ public final class CodedInputStream {
    * @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 {
+  public boolean skipField(final int tag) throws IOException {
     switch (WireFormat.getTagWireType(tag)) {
       case WireFormat.WIRETYPE_VARINT:
         readInt32();
@@ -143,8 +145,10 @@ public final class CodedInputStream {
    */
   public void skipMessage() throws IOException {
     while (true) {
-      int tag = readTag();
-      if (tag == 0 || !skipField(tag)) return;
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag)) {
+        return;
+      }
     }
   }
 
@@ -192,11 +196,11 @@ public final class CodedInputStream {
 
   /** Read a {@code string} field value from the stream. */
   public String readString() throws IOException {
-    int size = readRawVarint32();
+    final int size = readRawVarint32();
     if (size <= (bufferSize - bufferPos) && size > 0) {
       // Fast path:  We already have the bytes in a contiguous buffer, so
       //   just copy directly from it.
-      String result = new String(buffer, bufferPos, size, "UTF-8");
+      final String result = new String(buffer, bufferPos, size, "UTF-8");
       bufferPos += size;
       return result;
     } else {
@@ -206,8 +210,9 @@ public final class CodedInputStream {
   }
 
   /** Read a {@code group} field value from the stream. */
-  public void readGroup(int fieldNumber, Message.Builder builder,
-                        ExtensionRegistry extensionRegistry)
+  public void readGroup(final int fieldNumber,
+                        final MessageLite.Builder builder,
+                        final ExtensionRegistryLite extensionRegistry)
       throws IOException {
     if (recursionDepth >= recursionLimit) {
       throw InvalidProtocolBufferException.recursionLimitExceeded();
@@ -222,28 +227,31 @@ public final class CodedInputStream {
   /**
    * Reads a {@code group} field value from the stream and merges it into the
    * given {@link UnknownFieldSet}.
+   *
+   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
+   *             you can just call {@link #readGroup}.
    */
-  public void readUnknownGroup(int fieldNumber, UnknownFieldSet.Builder builder)
+  @Deprecated
+  public void readUnknownGroup(final int fieldNumber,
+                               final MessageLite.Builder builder)
       throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    builder.mergeFrom(this);
-    checkLastTagWas(
-      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-    --recursionDepth;
+    // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
+    // is safe to pass null here.  (We can't call
+    // ExtensionRegistry.getEmptyRegistry() because that would make this
+    // class depend on ExtensionRegistry, which is not part of the lite
+    // library.)
+    readGroup(fieldNumber, builder, null);
   }
 
   /** Read an embedded message field value from the stream. */
-  public void readMessage(Message.Builder builder,
-                          ExtensionRegistry extensionRegistry)
+  public void readMessage(final MessageLite.Builder builder,
+                          final ExtensionRegistryLite extensionRegistry)
       throws IOException {
-    int length = readRawVarint32();
+    final int length = readRawVarint32();
     if (recursionDepth >= recursionLimit) {
       throw InvalidProtocolBufferException.recursionLimitExceeded();
     }
-    int oldLimit = pushLimit(length);
+    final int oldLimit = pushLimit(length);
     ++recursionDepth;
     builder.mergeFrom(this, extensionRegistry);
     checkLastTagWas(0);
@@ -253,11 +261,11 @@ public final class CodedInputStream {
 
   /** Read a {@code bytes} field value from the stream. */
   public ByteString readBytes() throws IOException {
-    int size = readRawVarint32();
-    if (size < bufferSize - bufferPos && size > 0) {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
       // Fast path:  We already have the bytes in a contiguous buffer, so
       //   just copy directly from it.
-      ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
+      final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
       bufferPos += size;
       return result;
     } else {
@@ -299,52 +307,6 @@ public final class CodedInputStream {
     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.");
-  }
-
   // =================================================================
 
   /**
@@ -373,7 +335,9 @@ public final class CodedInputStream {
           if (tmp < 0) {
             // Discard upper 32 bits.
             for (int i = 0; i < 5; i++) {
-              if (readRawByte() >= 0) return result;
+              if (readRawByte() >= 0) {
+                return result;
+              }
             }
             throw InvalidProtocolBufferException.malformedVarint();
           }
@@ -390,11 +354,11 @@ public final class CodedInputStream {
    * then you would probably end up reading past the end of the varint since
    * CodedInputStream buffers its input.
    */
-  static int readRawVarint32(InputStream input) throws IOException {
+  static int readRawVarint32(final InputStream input) throws IOException {
     int result = 0;
     int offset = 0;
     for (; offset < 32; offset += 7) {
-      int b = input.read();
+      final int b = input.read();
       if (b == -1) {
         throw InvalidProtocolBufferException.truncatedMessage();
       }
@@ -405,7 +369,7 @@ public final class CodedInputStream {
     }
     // Keep reading up to 64 bits.
     for (; offset < 64; offset += 7) {
-      int b = input.read();
+      final int b = input.read();
       if (b == -1) {
         throw InvalidProtocolBufferException.truncatedMessage();
       }
@@ -421,9 +385,11 @@ public final class CodedInputStream {
     int shift = 0;
     long result = 0;
     while (shift < 64) {
-      byte b = readRawByte();
+      final byte b = readRawByte();
       result |= (long)(b & 0x7F) << shift;
-      if ((b & 0x80) == 0) return result;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
       shift += 7;
     }
     throw InvalidProtocolBufferException.malformedVarint();
@@ -431,10 +397,10 @@ public final class CodedInputStream {
 
   /** 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();
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
     return (((int)b1 & 0xff)      ) |
            (((int)b2 & 0xff) <<  8) |
            (((int)b3 & 0xff) << 16) |
@@ -443,14 +409,14 @@ public final class CodedInputStream {
 
   /** 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();
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
+    final byte b5 = readRawByte();
+    final byte b6 = readRawByte();
+    final byte b7 = readRawByte();
+    final byte b8 = readRawByte();
     return (((long)b1 & 0xff)      ) |
            (((long)b2 & 0xff) <<  8) |
            (((long)b3 & 0xff) << 16) |
@@ -471,7 +437,7 @@ public final class CodedInputStream {
    *          Java has no explicit unsigned support.
    * @return A signed 32-bit integer.
    */
-  public static int decodeZigZag32(int n) {
+  public static int decodeZigZag32(final int n) {
     return (n >>> 1) ^ -(n & 1);
   }
 
@@ -485,31 +451,31 @@ public final class CodedInputStream {
    *          Java has no explicit unsigned support.
    * @return A signed 64-bit integer.
    */
-  public static long decodeZigZag64(long n) {
+  public static long decodeZigZag64(final long n) {
     return (n >>> 1) ^ -(n & 1);
   }
 
   // -----------------------------------------------------------------
 
-  private byte[] buffer;
+  private final byte[] buffer;
   private int bufferSize;
-  private int bufferSizeAfterLimit = 0;
+  private int bufferSizeAfterLimit;
   private int bufferPos;
-  private InputStream input;
-  private int lastTag = 0;
+  private final InputStream input;
+  private int lastTag;
 
   /**
    * 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;
+  private int totalBytesRetired;
 
   /** The absolute position of the end of the current message. */
   private int currentLimit = Integer.MAX_VALUE;
 
   /** See setRecursionLimit() */
-  private int recursionDepth = 0;
+  private int recursionDepth;
   private int recursionLimit = DEFAULT_RECURSION_LIMIT;
 
   /** See setSizeLimit() */
@@ -519,17 +485,17 @@ public final class CodedInputStream {
   private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
   private static final int BUFFER_SIZE = 4096;
 
-  private CodedInputStream(byte[] buffer, int off, int len) {
+  private CodedInputStream(final byte[] buffer, final int off, final int len) {
     this.buffer = buffer;
-    this.bufferSize = off + len;
-    this.bufferPos = off;
-    this.input = null;
+    bufferSize = off + len;
+    bufferPos = off;
+    input = null;
   }
 
-  private CodedInputStream(InputStream input) {
-    this.buffer = new byte[BUFFER_SIZE];
-    this.bufferSize = 0;
-    this.bufferPos = 0;
+  private CodedInputStream(final InputStream input) {
+    buffer = new byte[BUFFER_SIZE];
+    bufferSize = 0;
+    bufferPos = 0;
     this.input = input;
   }
 
@@ -540,12 +506,12 @@ public final class CodedInputStream {
    *
    * @return the old limit.
    */
-  public int setRecursionLimit(int limit) {
+  public int setRecursionLimit(final int limit) {
     if (limit < 0) {
       throw new IllegalArgumentException(
         "Recursion limit cannot be negative: " + limit);
     }
-    int oldLimit = recursionLimit;
+    final int oldLimit = recursionLimit;
     recursionLimit = limit;
     return oldLimit;
   }
@@ -566,12 +532,12 @@ public final class CodedInputStream {
    *
    * @return the old limit.
    */
-  public int setSizeLimit(int limit) {
+  public int setSizeLimit(final int limit) {
     if (limit < 0) {
       throw new IllegalArgumentException(
         "Size limit cannot be negative: " + limit);
     }
-    int oldLimit = sizeLimit;
+    final int oldLimit = sizeLimit;
     sizeLimit = limit;
     return oldLimit;
   }
@@ -594,7 +560,7 @@ public final class CodedInputStream {
       throw InvalidProtocolBufferException.negativeSize();
     }
     byteLimit += totalBytesRetired + bufferPos;
-    int oldLimit = currentLimit;
+    final int oldLimit = currentLimit;
     if (byteLimit > oldLimit) {
       throw InvalidProtocolBufferException.truncatedMessage();
     }
@@ -607,7 +573,7 @@ public final class CodedInputStream {
 
   private void recomputeBufferSizeAfterLimit() {
     bufferSize += bufferSizeAfterLimit;
-    int bufferEnd = totalBytesRetired + bufferSize;
+    final int bufferEnd = totalBytesRetired + bufferSize;
     if (bufferEnd > currentLimit) {
       // Limit is in current buffer.
       bufferSizeAfterLimit = bufferEnd - currentLimit;
@@ -622,7 +588,7 @@ public final class CodedInputStream {
    *
    * @param oldLimit The old limit, as returned by {@code pushLimit}.
    */
-  public void popLimit(int oldLimit) {
+  public void popLimit(final int oldLimit) {
     currentLimit = oldLimit;
     recomputeBufferSizeAfterLimit();
   }
@@ -636,7 +602,7 @@ public final class CodedInputStream {
       return -1;
     }
 
-    int currentAbsolutePosition = totalBytesRetired + bufferPos;
+    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
     return currentLimit - currentAbsolutePosition;
   }
 
@@ -656,7 +622,7 @@ public final class CodedInputStream {
    * 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 {
+  private boolean refillBuffer(final boolean mustSucceed) throws IOException {
     if (bufferPos < bufferSize) {
       throw new IllegalStateException(
         "refillBuffer() called when buffer wasn't empty.");
@@ -689,7 +655,7 @@ public final class CodedInputStream {
       }
     } else {
       recomputeBufferSizeAfterLimit();
-      int totalBytesRead =
+      final int totalBytesRead =
         totalBytesRetired + bufferSize + bufferSizeAfterLimit;
       if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
         throw InvalidProtocolBufferException.sizeLimitExceeded();
@@ -717,7 +683,7 @@ public final class CodedInputStream {
    * @throws InvalidProtocolBufferException The end of the stream or the current
    *                                        limit was reached.
    */
-  public byte[] readRawBytes(int size) throws IOException {
+  public byte[] readRawBytes(final int size) throws IOException {
     if (size < 0) {
       throw InvalidProtocolBufferException.negativeSize();
     }
@@ -731,7 +697,7 @@ public final class CodedInputStream {
 
     if (size <= bufferSize - bufferPos) {
       // We have all the bytes we need already.
-      byte[] bytes = new byte[size];
+      final byte[] bytes = new byte[size];
       System.arraycopy(buffer, bufferPos, bytes, 0, size);
       bufferPos += size;
       return bytes;
@@ -740,7 +706,7 @@ public final class CodedInputStream {
       // of bytes.  We can safely allocate the resulting array ahead of time.
 
       // First copy what we have.
-      byte[] bytes = new byte[size];
+      final byte[] bytes = new byte[size];
       int pos = bufferSize - bufferPos;
       System.arraycopy(buffer, bufferPos, bytes, 0, pos);
       bufferPos = bufferSize;
@@ -772,8 +738,8 @@ public final class CodedInputStream {
 
       // Remember the buffer markers since we'll have to copy the bytes out of
       // it later.
-      int originalBufferPos = bufferPos;
-      int originalBufferSize = bufferSize;
+      final int originalBufferPos = bufferPos;
+      final int originalBufferSize = bufferSize;
 
       // Mark the current buffer consumed.
       totalBytesRetired += bufferSize;
@@ -782,13 +748,13 @@ public final class CodedInputStream {
 
       // Read all the rest of the bytes we need.
       int sizeLeft = size - (originalBufferSize - originalBufferPos);
-      List<byte[]> chunks = new ArrayList<byte[]>();
+      final List<byte[]> chunks = new ArrayList<byte[]>();
 
       while (sizeLeft > 0) {
-        byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
+        final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
         int pos = 0;
         while (pos < chunk.length) {
-          int n = (input == null) ? -1 :
+          final int n = (input == null) ? -1 :
             input.read(chunk, pos, chunk.length - pos);
           if (n == -1) {
             throw InvalidProtocolBufferException.truncatedMessage();
@@ -801,14 +767,14 @@ public final class CodedInputStream {
       }
 
       // OK, got everything.  Now concatenate it all into one buffer.
-      byte[] bytes = new byte[size];
+      final byte[] bytes = new byte[size];
 
       // Start by copying the leftover bytes from this.buffer.
       int pos = originalBufferSize - originalBufferPos;
       System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
 
       // And now all the chunks.
-      for (byte[] chunk : chunks) {
+      for (final byte[] chunk : chunks) {
         System.arraycopy(chunk, 0, bytes, pos, chunk.length);
         pos += chunk.length;
       }
@@ -824,7 +790,7 @@ public final class CodedInputStream {
    * @throws InvalidProtocolBufferException The end of the stream or the current
    *                                        limit was reached.
    */
-  public void skipRawBytes(int size) throws IOException {
+  public void skipRawBytes(final int size) throws IOException {
     if (size < 0) {
       throw InvalidProtocolBufferException.negativeSize();
     }
@@ -848,7 +814,7 @@ public final class CodedInputStream {
 
       // Then skip directly from the InputStream for the rest.
       while (pos < size) {
-        int n = (input == null) ? -1 : (int) input.skip(size - pos);
+        final int n = (input == null) ? -1 : (int) input.skip(size - pos);
         if (n <= 0) {
           throw InvalidProtocolBufferException.truncatedMessage();
         }

Разница между файлами не показана из-за своего большого размера
+ 174 - 240
java/src/main/java/com/google/protobuf/CodedOutputStream.java


Разница между файлами не показана из-за своего большого размера
+ 246 - 184
java/src/main/java/com/google/protobuf/Descriptors.java


+ 52 - 29
java/src/main/java/com/google/protobuf/DynamicMessage.java

@@ -45,14 +45,14 @@ import java.util.Map;
  */
 public final class DynamicMessage extends AbstractMessage {
   private final Descriptor type;
-  private final FieldSet fields;
+  private final FieldSet<FieldDescriptor> fields;
   private final UnknownFieldSet unknownFields;
   private int memoizedSize = -1;
 
   /**
    * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
    */
-  private DynamicMessage(Descriptor type, FieldSet fields,
+  private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
                          UnknownFieldSet unknownFields) {
     this.type = type;
     this.fields = fields;
@@ -64,7 +64,7 @@ public final class DynamicMessage extends AbstractMessage {
    * given type.
    */
   public static DynamicMessage getDefaultInstance(Descriptor type) {
-    return new DynamicMessage(type, FieldSet.emptySet(),
+    return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
                               UnknownFieldSet.getDefaultInstance());
   }
 
@@ -160,7 +160,11 @@ public final class DynamicMessage extends AbstractMessage {
     verifyContainingType(field);
     Object result = fields.getField(field);
     if (result == null) {
-      result = getDefaultInstance(field.getMessageType());
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        result = getDefaultInstance(field.getMessageType());
+      } else {
+        result = field.getDefaultValue();
+      }
     }
     return result;
   }
@@ -179,15 +183,31 @@ public final class DynamicMessage extends AbstractMessage {
     return unknownFields;
   }
 
+  private static boolean isInitialized(Descriptor type,
+                                       FieldSet<FieldDescriptor> fields) {
+    // Check that all required fields are present.
+    for (final FieldDescriptor field : type.getFields()) {
+      if (field.isRequired()) {
+        if (!fields.hasField(field)) {
+          return false;
+        }
+      }
+    }
+
+    // Check that embedded messages are initialized.
+    return fields.isInitialized();
+  }
+
   public boolean isInitialized() {
-    return fields.isInitialized(type);
+    return isInitialized(type, fields);
   }
 
   public void writeTo(CodedOutputStream output) throws IOException {
-    fields.writeTo(output);
     if (type.getOptions().getMessageSetWireFormat()) {
+      fields.writeMessageSetTo(output);
       unknownFields.writeAsMessageSetTo(output);
     } else {
+      fields.writeTo(output);
       unknownFields.writeTo(output);
     }
   }
@@ -196,10 +216,11 @@ public final class DynamicMessage extends AbstractMessage {
     int size = memoizedSize;
     if (size != -1) return size;
 
-    size = fields.getSerializedSize();
     if (type.getOptions().getMessageSetWireFormat()) {
+      size = fields.getMessageSetSerializedSize();
       size += unknownFields.getSerializedSizeAsMessageSet();
     } else {
+      size = fields.getSerializedSize();
       size += unknownFields.getSerializedSize();
     }
 
@@ -230,7 +251,7 @@ public final class DynamicMessage extends AbstractMessage {
    */
   public static final class Builder extends AbstractMessage.Builder<Builder> {
     private final Descriptor type;
-    private FieldSet fields;
+    private FieldSet<FieldDescriptor> fields;
     private UnknownFieldSet unknownFields;
 
     /** Construct a {@code Builder} for the given type. */
@@ -244,25 +265,33 @@ public final class DynamicMessage extends AbstractMessage {
     // Implementation of Message.Builder interface.
 
     public Builder clear() {
+      if (fields == null) {
+        throw new IllegalStateException("Cannot call clear() after build().");
+      }
       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.");
+      if (other instanceof DynamicMessage) {
+        // This should be somewhat faster than calling super.mergeFrom().
+        DynamicMessage otherDynamicMessage = (DynamicMessage) other;
+        if (otherDynamicMessage.type != type) {
+          throw new IllegalArgumentException(
+            "mergeFrom(Message) can only merge messages of the same type.");
+        }
+        fields.mergeFrom(otherDynamicMessage.fields);
+        mergeUnknownFields(otherDynamicMessage.unknownFields);
+        return this;
+      } else {
+        return super.mergeFrom(other);
       }
-
-      fields.mergeFrom(other);
-      mergeUnknownFields(other.getUnknownFields());
-      return this;
     }
 
     public DynamicMessage build() {
       // If fields == null, we'll throw an appropriate exception later.
       if (fields != null && !isInitialized()) {
-        throw new UninitializedMessageException(
+        throw newUninitializedMessageException(
           new DynamicMessage(type, fields, unknownFields));
       }
       return buildPartial();
@@ -275,7 +304,7 @@ public final class DynamicMessage extends AbstractMessage {
      */
     private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
       if (!isInitialized()) {
-        throw new UninitializedMessageException(
+        throw newUninitializedMessageException(
             new DynamicMessage(type, fields, unknownFields))
           .asInvalidProtocolBufferException();
       }
@@ -302,17 +331,7 @@ public final class DynamicMessage extends AbstractMessage {
     }
 
     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;
+      return DynamicMessage.isInitialized(type, fields);
     }
 
     public Descriptor getDescriptorForType() {
@@ -347,7 +366,11 @@ public final class DynamicMessage extends AbstractMessage {
       verifyContainingType(field);
       Object result = fields.getField(field);
       if (result == null) {
-        result = getDefaultInstance(field.getMessageType());
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          result = getDefaultInstance(field.getMessageType());
+        } else {
+          result = field.getDefaultValue();
+        }
       }
       return result;
     }

+ 45 - 35
java/src/main/java/com/google/protobuf/ExtensionRegistry.java

@@ -84,18 +84,16 @@ import java.util.Map;
  * 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
+ * type provided could be any arbitrary message class.  An unprivileged user
  * could take advantage of this to inject a mutable object into a message
- * belonging to priviledged code and create mischief.
+ * belonging to privileged code and create mischief.
  *
  * @author kenton@google.com Kenton Varda
  */
-public final class ExtensionRegistry {
+public final class ExtensionRegistry extends ExtensionRegistryLite {
   /** Construct a new, empty instance. */
   public static ExtensionRegistry newInstance() {
-    return new ExtensionRegistry(
-      new HashMap<String, ExtensionInfo>(),
-      new HashMap<DescriptorIntPair, ExtensionInfo>());
+    return new ExtensionRegistry();
   }
 
   /** Get the unmodifiable singleton empty instance. */
@@ -104,10 +102,9 @@ public final class ExtensionRegistry {
   }
 
   /** Returns an unmodifiable view of the registry. */
+  @Override
   public ExtensionRegistry getUnmodifiable() {
-    return new ExtensionRegistry(
-      Collections.unmodifiableMap(extensionsByName),
-      Collections.unmodifiableMap(extensionsByNumber));
+    return new ExtensionRegistry(this);
   }
 
   /** A (Descriptor, Message) pair, returned by lookup methods. */
@@ -121,11 +118,12 @@ public final class ExtensionRegistry {
      */
     public final Message defaultInstance;
 
-    private ExtensionInfo(FieldDescriptor descriptor) {
+    private ExtensionInfo(final FieldDescriptor descriptor) {
       this.descriptor = descriptor;
-      this.defaultInstance = null;
+      defaultInstance = null;
     }
-    private ExtensionInfo(FieldDescriptor descriptor, Message defaultInstance) {
+    private ExtensionInfo(final FieldDescriptor descriptor,
+                          final Message defaultInstance) {
       this.descriptor = descriptor;
       this.defaultInstance = defaultInstance;
     }
@@ -139,7 +137,7 @@ public final class ExtensionRegistry {
    * @return Information about the extension if found, or {@code null}
    *         otherwise.
    */
-  public ExtensionInfo findExtensionByName(String fullName) {
+  public ExtensionInfo findExtensionByName(final String fullName) {
     return extensionsByName.get(fullName);
   }
 
@@ -149,14 +147,14 @@ public final class ExtensionRegistry {
    * @return Information about the extension if found, or {@code null}
    *         otherwise.
    */
-  public ExtensionInfo findExtensionByNumber(Descriptor containingType,
-                                             int fieldNumber) {
+  public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
+                                             final 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) {
+  public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
     if (extension.getDescriptor().getJavaType() ==
         FieldDescriptor.JavaType.MESSAGE) {
       add(new ExtensionInfo(extension.getDescriptor(),
@@ -167,7 +165,7 @@ public final class ExtensionRegistry {
   }
 
   /** Add a non-message-type extension to the registry by descriptor. */
-  public void add(FieldDescriptor type) {
+  public void add(final FieldDescriptor type) {
     if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
       throw new IllegalArgumentException(
         "ExtensionRegistry.add() must be provided a default instance when " +
@@ -177,7 +175,7 @@ public final class ExtensionRegistry {
   }
 
   /** Add a message-type extension to the registry by descriptor. */
-  public void add(FieldDescriptor type, Message defaultInstance) {
+  public void add(final FieldDescriptor type, final Message defaultInstance) {
     if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
       throw new IllegalArgumentException(
         "ExtensionRegistry.add() provided a default instance for a " +
@@ -189,22 +187,30 @@ public final class ExtensionRegistry {
   // =================================================================
   // Private stuff.
 
-  private ExtensionRegistry(
-      Map<String, ExtensionInfo> extensionsByName,
-      Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber) {
-    this.extensionsByName = extensionsByName;
-    this.extensionsByNumber = extensionsByNumber;
+  private ExtensionRegistry() {
+    this.extensionsByName = new HashMap<String, ExtensionInfo>();
+    this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
+  }
+
+  private ExtensionRegistry(ExtensionRegistry other) {
+    super(other);
+    this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
+    this.extensionsByNumber =
+        Collections.unmodifiableMap(other.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 ExtensionRegistry(boolean empty) {
+    super(ExtensionRegistryLite.getEmptyRegistry());
+    this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
+    this.extensionsByNumber =
+        Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
+  }
+  private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
 
-  private void add(ExtensionInfo extension) {
+  private void add(final ExtensionInfo extension) {
     if (!extension.descriptor.isExtension()) {
       throw new IllegalArgumentException(
         "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
@@ -217,7 +223,7 @@ public final class ExtensionRegistry {
                             extension.descriptor.getNumber()),
       extension);
 
-    FieldDescriptor field = extension.descriptor;
+    final FieldDescriptor field = extension.descriptor;
     if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
         field.getType() == FieldDescriptor.Type.MESSAGE &&
         field.isOptional() &&
@@ -231,20 +237,24 @@ public final class ExtensionRegistry {
 
   /** A (GenericDescriptor, int) pair, used as a map key. */
   private static final class DescriptorIntPair {
-    final Descriptor descriptor;
-    final int number;
+    private final Descriptor descriptor;
+    private final int number;
 
-    DescriptorIntPair(Descriptor descriptor, int number) {
+    DescriptorIntPair(final Descriptor descriptor, final int number) {
       this.descriptor = descriptor;
       this.number = number;
     }
 
+    @Override
     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;
+    @Override
+    public boolean equals(final Object obj) {
+      if (!(obj instanceof DescriptorIntPair)) {
+        return false;
+      }
+      final DescriptorIntPair other = (DescriptorIntPair)obj;
       return descriptor == other.descriptor && number == other.number;
     }
   }

+ 169 - 0
java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java

@@ -0,0 +1,169 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
+ * <p>
+ * If all of your types are lite types, then you only need to use
+ * {@code ExtensionRegistryLite}.  Similarly, if all your types are regular
+ * types, then you only need {@link ExtensionRegistry}.  Typically it does not
+ * make sense to mix the two, since if you have any regular types in your
+ * program, you then require the full runtime and lose all the benefits of
+ * the lite runtime, so you might as well make all your types be regular types.
+ * However, in some cases (e.g. when depending on multiple third-patry libraries
+ * where one uses lite types and one uses regular), you may find yourself
+ * wanting to mix the two.  In this case things get more complicated.
+ * <p>
+ * There are three factors to consider:  Whether the type being extended is
+ * lite, whether the embedded type (in the case of a message-typed extension)
+ * is lite, and whether the extension itself is lite.  Since all three are
+ * declared in different files, they could all be different.  Here are all
+ * the combinations and which type of registry to use:
+ * <pre>
+ *   Extended type     Inner type    Extension         Use registry
+ *   =======================================================================
+ *   lite              lite          lite              ExtensionRegistryLite
+ *   lite              regular       lite              ExtensionRegistry
+ *   regular           regular       regular           ExtensionRegistry
+ *   all other combinations                            not supported
+ * </pre>
+ * <p>
+ * Note that just as regular types are not allowed to contain lite-type fields,
+ * they are also not allowed to contain lite-type extensions.  This is because
+ * regular types must be fully accessible via reflection, which in turn means
+ * that all the inner messages must also support reflection.  On the other hand,
+ * since regular types implement the entire lite interface, there is no problem
+ * with embedding regular types inside lite types.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ExtensionRegistryLite {
+  /** Construct a new, empty instance. */
+  public static ExtensionRegistryLite newInstance() {
+    return new ExtensionRegistryLite();
+  }
+
+  /** Get the unmodifiable singleton empty instance. */
+  public static ExtensionRegistryLite getEmptyRegistry() {
+    return EMPTY;
+  }
+
+  /** Returns an unmodifiable view of the registry. */
+  public ExtensionRegistryLite getUnmodifiable() {
+    return new ExtensionRegistryLite(this);
+  }
+
+  /**
+   * Find an extension by containing type and field number.
+   *
+   * @return Information about the extension if found, or {@code null}
+   *         otherwise.
+   */
+  @SuppressWarnings("unchecked")
+  public <ContainingType extends MessageLite>
+      GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
+        findLiteExtensionByNumber(
+          final ContainingType containingTypeDefaultInstance,
+          final int fieldNumber) {
+    return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
+      extensionsByNumber.get(
+        new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
+  }
+
+  /** Add an extension from a lite generated file to the registry. */
+  public final void add(
+      final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
+    extensionsByNumber.put(
+      new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
+                        extension.getNumber()),
+      extension);
+  }
+
+  // =================================================================
+  // Private stuff.
+
+  // Constructors are package-private so that ExtensionRegistry can subclass
+  // this.
+
+  ExtensionRegistryLite() {
+    this.extensionsByNumber =
+        new HashMap<ObjectIntPair,
+                    GeneratedMessageLite.GeneratedExtension<?, ?>>();
+  }
+
+  ExtensionRegistryLite(ExtensionRegistryLite other) {
+    if (other == EMPTY) {
+      this.extensionsByNumber = Collections.emptyMap();
+    } else {
+      this.extensionsByNumber =
+        Collections.unmodifiableMap(other.extensionsByNumber);
+    }
+  }
+
+  private final Map<ObjectIntPair,
+                    GeneratedMessageLite.GeneratedExtension<?, ?>>
+      extensionsByNumber;
+
+  private ExtensionRegistryLite(boolean empty) {
+    this.extensionsByNumber = Collections.emptyMap();
+  }
+  private static final ExtensionRegistryLite EMPTY =
+    new ExtensionRegistryLite(true);
+
+  /** A (Object, int) pair, used as a map key. */
+  private static final class ObjectIntPair {
+    private final Object object;
+    private final int number;
+
+    ObjectIntPair(final Object object, final int number) {
+      this.object = object;
+      this.number = number;
+    }
+
+    @Override
+    public int hashCode() {
+      return System.identityHashCode(object) * ((1 << 16) - 1) + number;
+    }
+    @Override
+    public boolean equals(final Object obj) {
+      if (!(obj instanceof ObjectIntPair)) {
+        return false;
+      }
+      final ObjectIntPair other = (ObjectIntPair)obj;
+      return object == other.object && number == other.number;
+    }
+  }
+}

+ 449 - 461
java/src/main/java/com/google/protobuf/FieldSet.java

@@ -30,16 +30,13 @@
 
 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;
+import java.io.IOException;
 
 /**
  * A class which represents an arbitrary set of fields of some message type.
@@ -49,43 +46,70 @@ import java.util.Map;
  *
  * @author kenton@google.com Kenton Varda
  */
-final class FieldSet {
-  private Map<FieldDescriptor, Object> fields;
+final class FieldSet<FieldDescriptorType extends
+      FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
+  /**
+   * Interface for a FieldDescriptor or lite extension descriptor.  This
+   * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
+   */
+  public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
+      extends Comparable<T> {
+    int getNumber();
+    WireFormat.FieldType getLiteType();
+    WireFormat.JavaType getLiteJavaType();
+    boolean isRepeated();
+    boolean isPacked();
+    Internal.EnumLiteMap<?> getEnumType();
+
+    // If getLiteJavaType() == MESSAGE, this merges a message object of the
+    // type into a builder of the type.  Returns {@code to}.
+    MessageLite.Builder internalMergeFrom(
+        MessageLite.Builder to, MessageLite from);
+  }
+
+  private Map<FieldDescriptorType, 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>();
+    // TODO(kenton):  Maybe use some sort of sparse array instead?  It would
+    //   even make sense to store the first 16 or so tags in a flat array
+    //   to make DynamicMessage faster.
+    fields = new TreeMap<FieldDescriptorType, Object>();
   }
 
   /**
-   * Construct a new FieldSet with the given map.  This is only used by
-   * DEFAULT_INSTANCE, to pass in an immutable empty map.
+   * Construct an empty FieldSet.  This is only used to initialize
+   * DEFAULT_INSTANCE.
    */
-  private FieldSet(Map<FieldDescriptor, Object> fields) {
-    this.fields = fields;
+  private FieldSet(final boolean dummy) {
+    this.fields = Collections.emptyMap();
   }
 
   /** Construct a new FieldSet. */
-  public static FieldSet newFieldSet() {
-    return new FieldSet();
+  public static <T extends FieldSet.FieldDescriptorLite<T>>
+      FieldSet<T> newFieldSet() {
+    return new FieldSet<T>();
   }
 
   /** Get an immutable empty FieldSet. */
-  public static FieldSet emptySet() {
+  @SuppressWarnings("unchecked")
+  public static <T extends FieldSet.FieldDescriptorLite<T>>
+      FieldSet<T> emptySet() {
     return DEFAULT_INSTANCE;
   }
-  private static final FieldSet DEFAULT_INSTANCE =
-    new FieldSet(Collections.<FieldDescriptor, Object>emptyMap());
+  @SuppressWarnings("unchecked")
+  private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
 
   /** Make this FieldSet immutable from this point forward. */
   @SuppressWarnings("unchecked")
   public void makeImmutable() {
-    for (Map.Entry<FieldDescriptor, Object> entry: fields.entrySet()) {
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
       if (entry.getKey().isRepeated()) {
-        List value = (List)entry.getValue();
-        entry.setValue(Collections.unmodifiableList(value));
+        final List value = (List)entry.getValue();
+        fields.put(entry.getKey(), Collections.unmodifiableList(value));
       }
     }
     fields = Collections.unmodifiableMap(fields);
@@ -98,56 +122,52 @@ final class FieldSet {
     fields.clear();
   }
 
-  /** See {@link Message#getAllFields()}. */
-  public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+  /**
+   * Get a simple map containing all the fields.
+   */
+  public Map<FieldDescriptorType, Object> getAllFields() {
     return Collections.unmodifiableMap(fields);
   }
 
   /**
-   * Get an interator to the field map.  This iterator should not be leaked
+   * Get an iterator to the field map.  This iterator should not be leaked
    * out of the protobuf library as it is not protected from mutation.
    */
-  public Iterator<Map.Entry<Descriptors.FieldDescriptor, Object>> iterator() {
+  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
     return fields.entrySet().iterator();
   }
 
-  /** See {@link Message#hasField(Descriptors.FieldDescriptor)}. */
-  public boolean hasField(Descriptors.FieldDescriptor field) {
-    if (field.isRepeated()) {
+  /**
+   * Useful for implementing
+   * {@link Message#hasField(Descriptors.FieldDescriptor)}.
+   */
+  public boolean hasField(final FieldDescriptorType descriptor) {
+    if (descriptor.isRepeated()) {
       throw new IllegalArgumentException(
         "hasField() can only be called on non-repeated fields.");
     }
 
-    return fields.containsKey(field);
+    return fields.get(descriptor) != null;
   }
 
   /**
-   * 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.
+   * Useful for implementing
+   * {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
+   * returns {@code null} if the field is not set; in this case it is up
+   * to the caller to fetch the field's default value.
    */
-  public Object getField(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;
-    }
+  public Object getField(final FieldDescriptorType descriptor) {
+    return fields.get(descriptor);
   }
 
-  /** See {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}. */
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
+   */
   @SuppressWarnings("unchecked")
-  public void setField(Descriptors.FieldDescriptor field, Object value) {
-    if (field.isRepeated()) {
+  public void setField(final FieldDescriptorType descriptor,
+                       Object value) {
+    if (descriptor.isRepeated()) {
       if (!(value instanceof List)) {
         throw new IllegalArgumentException(
           "Wrong object type used with protocol message reflection.");
@@ -155,78 +175,108 @@ final class FieldSet {
 
       // Wrap the contents in a new list so that the caller cannot change
       // the list's contents after setting it.
-      List newList = new ArrayList();
+      final List newList = new ArrayList();
       newList.addAll((List)value);
-      for (Object element : newList) {
-        verifyType(field, element);
+      for (final Object element : newList) {
+        verifyType(descriptor.getLiteType(), element);
       }
       value = newList;
     } else {
-      verifyType(field, value);
+      verifyType(descriptor.getLiteType(), value);
     }
 
-    fields.put(field, value);
+    fields.put(descriptor, value);
   }
 
-  /** See {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
-  public void clearField(Descriptors.FieldDescriptor field) {
-    fields.remove(field);
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
+   */
+  public void clearField(final FieldDescriptorType descriptor) {
+    fields.remove(descriptor);
   }
 
-  /** See {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
-  public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
-    if (!field.isRepeated()) {
+  /**
+   * Useful for implementing
+   * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
+   */
+  public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
+    if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
-        "getRepeatedFieldCount() can only be called on repeated fields.");
+        "getRepeatedField() can only be called on repeated fields.");
     }
 
-    return ((List)getField(field)).size();
+    final Object value = fields.get(descriptor);
+    if (value == null) {
+      return 0;
+    } else {
+      return ((List) value).size();
+    }
   }
 
-  /** See {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
-  public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
-    if (!field.isRepeated()) {
+  /**
+   * Useful for implementing
+   * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
+   */
+  public Object getRepeatedField(final FieldDescriptorType descriptor,
+                                 final int index) {
+    if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
         "getRepeatedField() can only be called on repeated fields.");
     }
 
-    return ((List)getField(field)).get(index);
+    final Object value = fields.get(descriptor);
+
+    if (value == null) {
+      throw new IndexOutOfBoundsException();
+    } else {
+      return ((List) value).get(index);
+    }
   }
 
-  /** See {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}. */
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
+   */
   @SuppressWarnings("unchecked")
-  public void setRepeatedField(Descriptors.FieldDescriptor field, int index,
-                               Object value) {
-    if (!field.isRepeated()) {
+  public void setRepeatedField(final FieldDescriptorType descriptor,
+                               final int index,
+                               final Object value) {
+    if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
-        "setRepeatedField() can only be called on repeated fields.");
+        "getRepeatedField() can only be called on repeated fields.");
     }
 
-    verifyType(field, value);
-
-    List list = (List)fields.get(field);
+    final Object list = fields.get(descriptor);
     if (list == null) {
       throw new IndexOutOfBoundsException();
     }
 
-    list.set(index, value);
+    verifyType(descriptor.getLiteType(), value);
+    ((List) list).set(index, value);
   }
 
-  /** See {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}. */
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
+   */
   @SuppressWarnings("unchecked")
-  public void addRepeatedField(Descriptors.FieldDescriptor field,
-                               Object value) {
-    if (!field.isRepeated()) {
+  public void addRepeatedField(final FieldDescriptorType descriptor,
+                               final Object value) {
+    if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
-        "setRepeatedField() can only be called on repeated fields.");
+        "addRepeatedField() can only be called on repeated fields.");
     }
 
-    verifyType(field, value);
+    verifyType(descriptor.getLiteType(), value);
 
-    List list = (List)fields.get(field);
-    if (list == null) {
+    final Object existingValue = fields.get(descriptor);
+    List list;
+    if (existingValue == null) {
       list = new ArrayList();
-      fields.put(field, list);
+      fields.put(descriptor, list);
+    } else {
+      list = (List) existingValue;
     }
 
     list.add(value);
@@ -239,9 +289,14 @@ final class FieldSet {
    *
    * @throws IllegalArgumentException The value is not of the right type.
    */
-  private void verifyType(FieldDescriptor field, Object value) {
+  private static void verifyType(final WireFormat.FieldType type,
+                                 final Object value) {
+    if (value == null) {
+      throw new NullPointerException();
+    }
+
     boolean isValid = false;
-    switch (field.getJavaType()) {
+    switch (type.getJavaType()) {
       case INT:          isValid = value instanceof Integer   ; break;
       case LONG:         isValid = value instanceof Long      ; break;
       case FLOAT:        isValid = value instanceof Float     ; break;
@@ -250,26 +305,25 @@ final class FieldSet {
       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();
+        // TODO(kenton):  Caller must do type checking here, I guess.
+        isValid = value instanceof Internal.EnumLite;
         break;
       case MESSAGE:
-        isValid = value instanceof Message &&
-          ((Message)value).getDescriptorForType() == field.getMessageType();
+        // TODO(kenton):  Caller must do type checking here, I guess.
+        isValid = value instanceof MessageLite;
         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.
+      // TODO(kenton):  When chaining calls to setField(), it can be hard to
+      //   tell from the stack trace which exact call failed, since the whole
+      //   chain is considered one line of code.  It would be nice to print
+      //   more information here, e.g. naming the field.  We used to do that.
+      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
+      //   isn't a big deal, though, since it would only really apply when using
+      //   reflection and generally people don't chain reflection setters.
       throw new IllegalArgumentException(
-        "Wrong object type used with protocol message reflection.  " +
-        "Message type \"" + field.getContainingType().getFullName() +
-        "\", field \"" +
-        (field.isExtension() ? field.getFullName() : field.getName()) +
-        "\", value was type \"" + value.getClass().getName() + "\".");
+        "Wrong object type used with protocol message reflection.");
     }
   }
 
@@ -284,17 +338,19 @@ final class FieldSet {
    */
   @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()) {
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
+      final FieldDescriptorType descriptor = entry.getKey();
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+        if (descriptor.isRepeated()) {
+          for (final MessageLite element:
+               (List<MessageLite>) entry.getValue()) {
             if (!element.isInitialized()) {
               return false;
             }
           }
         } else {
-          if (!((Message) entry.getValue()).isInitialized()) {
+          if (!((MessageLite) entry.getValue()).isInitialized()) {
             return false;
           }
         }
@@ -305,59 +361,17 @@ final class FieldSet {
   }
 
   /**
-   * Like {@link #isInitialized()}, but also checks for the presence of
-   * all required fields in the given type.
+   * Given a field type, return the wire type.
+   *
+   * @returns One of the {@code WIRETYPE_} constants defined in
+   *          {@link WireFormat}.
    */
-  @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.toBuilder()
-              .mergeFrom((Message)entry.getValue())
-              .build());
-        }
-      } else {
-        setField(field, entry.getValue());
-      }
+  static int getWireFormatForFieldType(final WireFormat.FieldType type,
+                                       boolean isPacked) {
+    if (isPacked) {
+      return WireFormat.WIRETYPE_LENGTH_DELIMITED;
+    } else {
+      return type.getWireType();
     }
   }
 
@@ -365,360 +379,334 @@ final class FieldSet {
    * 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);
+  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         other.fields.entrySet()) {
+      final FieldDescriptorType descriptor = entry.getKey();
+      final Object otherValue = entry.getValue();
+
+      if (descriptor.isRepeated()) {
+        Object value = fields.get(descriptor);
+        if (value == null) {
+          // Our list is empty, but we still need to make a defensive copy of
+          // the other list since we don't know if the other FieldSet is still
+          // mutable.
+          fields.put(descriptor, new ArrayList((List) otherValue));
+        } else {
+          // Concatenate the lists.
+          ((List) value).addAll((List) otherValue);
         }
-        existingValue.addAll((List)value);
-      } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        Message existingValue = (Message)fields.get(field);
-        if (existingValue == null) {
-          setField(field, value);
+      } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+        Object value = fields.get(descriptor);
+        if (value == null) {
+          fields.put(descriptor, otherValue);
         } else {
-          setField(field,
-            existingValue.toBuilder()
-              .mergeFrom((Message)value)
+          // Merge the messages.
+          fields.put(descriptor,
+              descriptor.internalMergeFrom(
+                ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
               .build());
         }
+
       } else {
-        setField(field, value);
+        fields.put(descriptor, otherValue);
       }
     }
   }
 
-  // TODO(kenton):  Move parsing code into AbstractMessage, since it no longer
-  //   uses any special knowledge from FieldSet.
+  // TODO(kenton):  Move static parsing and serialization methods into some
+  //   other class.  Probably WireFormat.
 
   /**
-   * See {@link Message.Builder#mergeFrom(CodedInputStream)}.
-   * @param builder The {@code Builder} for the target message.
+   * Read a field of any primitive type from a CodedInputStream.  Enums,
+   * groups, and embedded messages are not handled by this method.
+   *
+   * @param input The stream from which to read.
+   * @param type Declared type of the field.
+   * @return An object representing the field's value, of the exact
+   *         type which would be returned by
+   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *         this field.
    */
-  public static 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;
-      }
+  public static Object readPrimitiveField(
+      CodedInputStream input,
+      final WireFormat.FieldType type) throws IOException {
+    switch (type) {
+      case DOUBLE  : return input.readDouble  ();
+      case FLOAT   : return input.readFloat   ();
+      case INT64   : return input.readInt64   ();
+      case UINT64  : return input.readUInt64  ();
+      case INT32   : return input.readInt32   ();
+      case FIXED64 : return input.readFixed64 ();
+      case FIXED32 : return input.readFixed32 ();
+      case BOOL    : return input.readBool    ();
+      case STRING  : return input.readString  ();
+      case BYTES   : return input.readBytes   ();
+      case UINT32  : return input.readUInt32  ();
+      case SFIXED32: return input.readSFixed32();
+      case SFIXED64: return input.readSFixed64();
+      case SINT32  : return input.readSInt32  ();
+      case SINT64  : return input.readSInt64  ();
+
+      case GROUP:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle nested groups.");
+      case MESSAGE:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle embedded messages.");
+      case ENUM:
+        // We don't handle enums because we don't know what to do if the
+        // value is not recognized.
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle enums.");
+    }
 
-      if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
-                          builder, tag)) {
-        // end group tag
-        break;
-      }
+    throw new RuntimeException(
+      "There is no way to get here, but the compiler thinks otherwise.");
+  }
+
+  /** See {@link Message#writeTo(CodedOutputStream)}. */
+  public void writeTo(final CodedOutputStream output)
+                      throws IOException {
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
+      writeField(entry.getKey(), entry.getValue(), output);
     }
   }
 
   /**
-   * 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.
+   * Like {@link #writeTo} but uses MessageSet wire format.
    */
-  @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;
+  public void writeMessageSetTo(final CodedOutputStream output)
+                                throws IOException {
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
+      final FieldDescriptorType descriptor = entry.getKey();
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
+          !descriptor.isRepeated() && !descriptor.isPacked()) {
+        output.writeMessageSetExtension(entry.getKey().getNumber(),
+                                        (MessageLite) entry.getValue());
       } else {
-        field = extension.descriptor;
-        defaultInstance = extension.defaultInstance;
+        writeField(descriptor, entry.getValue(), output);
       }
-    } else {
-      field = type.findFieldByNumber(fieldNumber);
     }
+  }
 
-    if (field == null ||
-        wireType != WireFormat.getWireFormatForField(field)) {
-      // Unknown field or wrong wire type.  Skip.
-      return unknownFields.mergeFieldFrom(tag, input);
+  /**
+   * Write a single tag-value pair to the stream.
+   *
+   * @param output The output stream.
+   * @param type   The field's type.
+   * @param number The field's number.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  private static void writeElement(final CodedOutputStream output,
+                                   final WireFormat.FieldType type,
+                                   final int number,
+                                   final Object value) throws IOException {
+    // Special case for groups, which need a start and end tag; other fields
+    // can just use writeTag() and writeFieldNoTag().
+    if (type == WireFormat.FieldType.GROUP) {
+      output.writeGroup(number, (MessageLite) value);
     } else {
-      if (field.getOptions().getPacked()) {
-        int length = input.readRawVarint32();
-        int limit = input.pushLimit(length);
-        if (field.getType() == FieldDescriptor.Type.ENUM) {
-          while (input.getBytesUntilLimit() > 0) {
-            int rawValue = input.readEnum();
-            Object value = field.getEnumType().findValueByNumber(rawValue);
-            if (value == null) {
-              // If the number isn't recognized as a valid value for this
-              // enum, drop it (don't even add it to unknownFields).
-              return true;
-            }
-            builder.addRepeatedField(field, value);
-          }
-        } else {
-          while (input.getBytesUntilLimit() > 0) {
-            Object value = input.readPrimitiveField(field.getType());
-            builder.addRepeatedField(field, value);
-          }
-        }
-        input.popLimit(limit);
-      } 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);
-        }
-      }
+      output.writeTag(number, getWireFormatForFieldType(type, false));
+      writeElementNoTag(output, type, 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) {
+  /**
+   * Write a field of arbitrary type, without its tag, to the stream.
+   *
+   * @param output The output stream.
+   * @param type The field's type.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  private static void writeElementNoTag(
+      final CodedOutputStream output,
+      final WireFormat.FieldType type,
+      final Object value) throws IOException {
+    switch (type) {
+      case DOUBLE  : output.writeDoubleNoTag  ((Double     ) value); break;
+      case FLOAT   : output.writeFloatNoTag   ((Float      ) value); break;
+      case INT64   : output.writeInt64NoTag   ((Long       ) value); break;
+      case UINT64  : output.writeUInt64NoTag  ((Long       ) value); break;
+      case INT32   : output.writeInt32NoTag   ((Integer    ) value); break;
+      case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
+      case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
+      case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
+      case STRING  : output.writeStringNoTag  ((String     ) value); break;
+      case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
+      case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
+      case BYTES   : output.writeBytesNoTag   ((ByteString ) value); break;
+      case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
+      case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
+      case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
+      case SINT32  : output.writeSInt32NoTag  ((Integer    ) value); break;
+      case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
+
+      case ENUM:
+        output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
         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;
-            }
-          }
+  /** Write a single field. */
+  public static void writeField(final FieldDescriptorLite<?> descriptor,
+                                final Object value,
+                                final CodedOutputStream output)
+                                throws IOException {
+    WireFormat.FieldType type = descriptor.getLiteType();
+    int number = descriptor.getNumber();
+    if (descriptor.isRepeated()) {
+      final List valueList = (List)value;
+      if (descriptor.isPacked()) {
+        output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+        // Compute the total data size so the length can be written.
+        int dataSize = 0;
+        for (final Object element : valueList) {
+          dataSize += computeElementSizeNoTag(type, element);
         }
-      } 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);
+        output.writeRawVarint32(dataSize);
+        // Write the data itself, without any tags.
+        for (final Object element : valueList) {
+          writeElementNoTag(output, type, element);
         }
       } else {
-        // Unknown tag.  Skip it.
-        if (!input.skipField(tag)) {
-          break;  // end of group
+        for (final Object element : valueList) {
+          writeElement(output, type, number, element);
         }
       }
-    }
-
-    input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
-
-    if (subBuilder != null) {
-      builder.setField(field, subBuilder.build());
+    } else {
+      writeElement(output, type, number, value);
     }
   }
 
-  /** 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);
+  /**
+   * See {@link Message#getSerializedSize()}.  It's up to the caller to cache
+   * the resulting size if desired.
+   */
+  public int getSerializedSize() {
+    int size = 0;
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
+      size += computeFieldSize(entry.getKey(), entry.getValue());
     }
+    return size;
   }
 
-  /** 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()) {
-        List valueList = (List)value;
-        if (field.getOptions().getPacked()) {
-          output.writeTag(field.getNumber(),
-                          WireFormat.WIRETYPE_LENGTH_DELIMITED);
-          // Compute the total data size so the length can be written.
-          int dataSize = 0;
-          for (Object element : valueList) {
-            dataSize += output.computeFieldSizeNoTag(field.getType(), element);
-          }
-          output.writeRawVarint32(dataSize);
-          // Write the data itself, without any tags.
-          for (Object element : valueList) {
-            output.writeFieldNoTag(field.getType(), element);
-          }
-        } else {
-          for (Object element : valueList) {
-            output.writeField(field.getType(), field.getNumber(), element);
-          }
-        }
+  /**
+   * Like {@link #getSerializedSize} but uses MessageSet wire format.
+   */
+  public int getMessageSetSerializedSize() {
+    int size = 0;
+    for (final Map.Entry<FieldDescriptorType, Object> entry:
+         fields.entrySet()) {
+      final FieldDescriptorType descriptor = entry.getKey();
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
+          !descriptor.isRepeated() && !descriptor.isPacked()) {
+        size += CodedOutputStream.computeMessageSetExtensionSize(
+                  entry.getKey().getNumber(), (MessageLite) entry.getValue());
       } else {
-        output.writeField(field.getType(), field.getNumber(), value);
+        size += computeFieldSize(descriptor, entry.getValue());
       }
     }
+    return size;
   }
 
   /**
-   * See {@link Message#getSerializedSize()}.  It's up to the caller to cache
-   * the resulting size if desired.
+   * Compute the number of bytes that would be needed to encode a
+   * single tag/value pair of arbitrary type.
+   *
+   * @param type   The field's type.
+   * @param number The field's number.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
    */
-  public int getSerializedSize() {
-    int size = 0;
-    for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
-      FieldDescriptor field = entry.getKey();
-      Object value = entry.getValue();
+  private static int computeElementSize(
+      final WireFormat.FieldType type,
+      final int number, final Object value) {
+    int tagSize = CodedOutputStream.computeTagSize(number);
+    if (type == WireFormat.FieldType.GROUP) {
+      tagSize *= 2;
+    }
+    return tagSize + computeElementSizeNoTag(type, value);
+  }
 
-      if (field.isExtension() &&
-          field.getContainingType().getOptions().getMessageSetWireFormat()) {
-        size += CodedOutputStream.computeMessageSetExtensionSize(
-          field.getNumber(), (Message) value);
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * particular value of arbitrary type, excluding tag.
+   *
+   * @param type   The field's type.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  private static int computeElementSizeNoTag(
+      final WireFormat.FieldType type, final Object value) {
+    switch (type) {
+      // Note:  Minor violation of 80-char limit rule here because this would
+      //   actually be harder to read if we wrapped the lines.
+      case DOUBLE  : return CodedOutputStream.computeDoubleSizeNoTag  ((Double     )value);
+      case FLOAT   : return CodedOutputStream.computeFloatSizeNoTag   ((Float      )value);
+      case INT64   : return CodedOutputStream.computeInt64SizeNoTag   ((Long       )value);
+      case UINT64  : return CodedOutputStream.computeUInt64SizeNoTag  ((Long       )value);
+      case INT32   : return CodedOutputStream.computeInt32SizeNoTag   ((Integer    )value);
+      case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
+      case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
+      case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
+      case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
+      case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
+      case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
+      case BYTES   : return CodedOutputStream.computeBytesSizeNoTag   ((ByteString )value);
+      case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
+      case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
+      case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
+      case SINT32  : return CodedOutputStream.computeSInt32SizeNoTag  ((Integer    )value);
+      case SINT64  : return CodedOutputStream.computeSInt64SizeNoTag  ((Long       )value);
+
+      case ENUM:
+        return CodedOutputStream.computeEnumSizeNoTag(
+            ((Internal.EnumLite) value).getNumber());
+    }
+
+    throw new RuntimeException(
+      "There is no way to get here, but the compiler thinks otherwise.");
+  }
+
+  /**
+   * Compute the number of bytes needed to encode a particular field.
+   */
+  public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
+                                     final Object value) {
+    WireFormat.FieldType type = descriptor.getLiteType();
+    int number = descriptor.getNumber();
+    if (descriptor.isRepeated()) {
+      if (descriptor.isPacked()) {
+        int dataSize = 0;
+        for (final Object element : (List)value) {
+          dataSize += computeElementSizeNoTag(type, element);
+        }
+        return dataSize +
+            CodedOutputStream.computeTagSize(number) +
+            CodedOutputStream.computeRawVarint32Size(dataSize);
       } else {
-        if (field.isRepeated()) {
-          if (field.getOptions().getPacked()) {
-            int dataSize = 0;
-            for (Object element : (List)value) {
-              dataSize += CodedOutputStream.computeFieldSizeNoTag(
-                  field.getType(), element);
-            }
-            size += dataSize +
-                CodedOutputStream.computeTagSize(field.getNumber()) +
-                CodedOutputStream.computeRawVarint32Size(dataSize);
-          } else {
-            for (Object element : (List)value) {
-              size += CodedOutputStream.computeFieldSize(
-                  field.getType(), field.getNumber(), element);
-            }
-          }
-        } else {
-          size += CodedOutputStream.computeFieldSize(
-            field.getType(), field.getNumber(), value);
+        int size = 0;
+        for (final Object element : (List)value) {
+          size += computeElementSize(type, number, element);
         }
+        return size;
       }
+    } else {
+      return computeElementSize(type, number, value);
     }
-    return size;
   }
 }

Разница между файлами не показана из-за своего большого размера
+ 249 - 224
java/src/main/java/com/google/protobuf/GeneratedMessage.java


+ 539 - 0
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -0,0 +1,539 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Lite version of {@link GeneratedMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessageLite extends AbstractMessageLite {
+  protected GeneratedMessageLite() {}
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder<MessageType extends GeneratedMessageLite,
+                                       BuilderType extends Builder>
+      extends AbstractMessageLite.Builder<BuilderType> {
+    protected Builder() {}
+
+    // This is implemented here only to work around an apparent bug in the
+    // Java compiler and/or build system.  See bug #1898463.  The mere presence
+    // of this dummy clone() implementation makes it go away.
+    @Override
+    public BuilderType clone() {
+      throw new UnsupportedOperationException(
+          "This is supposed to be overridden by subclasses.");
+    }
+
+    /** All subclasses implement this. */
+    public abstract BuilderType mergeFrom(MessageType message);
+
+    // Defined here for return type covariance.
+    public abstract MessageType getDefaultInstanceForType();
+
+    /**
+     * Get the message being built.  We don't just pass this to the
+     * constructor because it becomes null when build() is called.
+     */
+    protected abstract MessageType internalGetResult();
+
+    /**
+     * Called by subclasses to parse an unknown field.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      return input.skipField(tag);
+    }
+  }
+
+  // =================================================================
+  // Extensions-related stuff
+
+  /**
+   * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
+   */
+  public abstract static class ExtendableMessage<
+        MessageType extends ExtendableMessage<MessageType>>
+      extends GeneratedMessageLite {
+    protected ExtendableMessage() {}
+    private final FieldSet<ExtensionDescriptor> extensions =
+        FieldSet.newFieldSet();
+
+    private void verifyExtensionContainingType(
+        final GeneratedExtension<MessageType, ?> extension) {
+      if (extension.getContainingTypeDefaultInstance() !=
+          getDefaultInstanceForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "This extension is for a different message type.  Please make " +
+          "sure that you are not suppressing any generics type warnings.");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    public final boolean hasExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.descriptor);
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      verifyExtensionContainingType(extension);
+      return extensions.getRepeatedFieldCount(extension.descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      verifyExtensionContainingType(extension);
+      final Object value = extensions.getField(extension.descriptor);
+      if (value == null) {
+        return extension.defaultValue;
+      } else {
+        return (Type) value;
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index) {
+      verifyExtensionContainingType(extension);
+      return (Type) extensions.getRepeatedField(extension.descriptor, 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.
+
+      private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
+            extensions.iterator();
+      private Map.Entry<ExtensionDescriptor, Object> next;
+      private final boolean messageSetWireFormat;
+
+      private ExtensionWriter(boolean messageSetWireFormat) {
+        if (iter.hasNext()) {
+          next = iter.next();
+        }
+        this.messageSetWireFormat = messageSetWireFormat;
+      }
+
+      public void writeUntil(final int end, final CodedOutputStream output)
+                             throws IOException {
+        while (next != null && next.getKey().getNumber() < end) {
+          ExtensionDescriptor extension = next.getKey();
+          if (messageSetWireFormat && extension.getLiteJavaType() ==
+                  WireFormat.JavaType.MESSAGE &&
+              !extension.isRepeated()) {
+            output.writeMessageSetExtension(extension.getNumber(),
+                                            (MessageLite) next.getValue());
+          } else {
+            FieldSet.writeField(extension, next.getValue(), output);
+          }
+          if (iter.hasNext()) {
+            next = iter.next();
+          } else {
+            next = null;
+          }
+        }
+      }
+    }
+
+    protected ExtensionWriter newExtensionWriter() {
+      return new ExtensionWriter(false);
+    }
+    protected ExtensionWriter newMessageSetExtensionWriter() {
+      return new ExtensionWriter(true);
+    }
+
+    /** Called by subclasses to compute the size of extensions. */
+    protected int extensionsSerializedSize() {
+      return extensions.getSerializedSize();
+    }
+    protected int extensionsSerializedSizeAsMessageSet() {
+      return extensions.getMessageSetSerializedSize();
+    }
+  }
+
+  /**
+   * Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class ExtendableBuilder<
+        MessageType extends ExtendableMessage<MessageType>,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+      extends Builder<MessageType, BuilderType> {
+    protected ExtendableBuilder() {}
+
+    // This is implemented here only to work around an apparent bug in the
+    // Java compiler and/or build system.  See bug #1898463.  The mere presence
+    // of this dummy clone() implementation makes it go away.
+    @Override
+    public BuilderType clone() {
+      throw new UnsupportedOperationException(
+          "This is supposed to be overridden by subclasses.");
+    }
+
+    @Override
+    protected abstract MessageType internalGetResult();
+
+    /** Check if a singular extension is present. */
+    public final boolean hasExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      return internalGetResult().hasExtension(extension);
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return internalGetResult().getExtensionCount(extension);
+    }
+
+    /** Get the value of an extension. */
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return internalGetResult().getExtension(extension);
+    }
+
+    /** Get one element of a repeated extension. */
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index) {
+      return internalGetResult().getExtension(extension, index);
+    }
+
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, Type> extension,
+        final Type value) {
+      final ExtendableMessage<MessageType> message = internalGetResult();
+      message.verifyExtensionContainingType(extension);
+      message.extensions.setField(extension.descriptor, value);
+      return (BuilderType) this;
+    }
+
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      final ExtendableMessage<MessageType> message = internalGetResult();
+      message.verifyExtensionContainingType(extension);
+      message.extensions.setRepeatedField(extension.descriptor, index, value);
+      return (BuilderType) this;
+    }
+
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final Type value) {
+      final ExtendableMessage<MessageType> message = internalGetResult();
+      message.verifyExtensionContainingType(extension);
+      message.extensions.addRepeatedField(extension.descriptor, value);
+      return (BuilderType) this;
+    }
+
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      final ExtendableMessage<MessageType> message = internalGetResult();
+      message.verifyExtensionContainingType(extension);
+      message.extensions.clearField(extension.descriptor);
+      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.
+     */
+    @Override
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      final FieldSet<ExtensionDescriptor> extensions =
+          internalGetResult().extensions;
+
+      final int wireType = WireFormat.getTagWireType(tag);
+      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+      final GeneratedExtension<MessageType, ?> extension =
+        extensionRegistry.findLiteExtensionByNumber(
+            getDefaultInstanceForType(), fieldNumber);
+
+      if (extension == null || wireType !=
+            FieldSet.getWireFormatForFieldType(
+                extension.descriptor.getLiteType(),
+                extension.descriptor.isPacked())) {
+        // Unknown field or wrong wire type.  Skip.
+        return input.skipField(tag);
+      }
+
+      if (extension.descriptor.isPacked()) {
+        final int length = input.readRawVarint32();
+        final int limit = input.pushLimit(length);
+        if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+          while (input.getBytesUntilLimit() > 0) {
+            final int rawValue = input.readEnum();
+            final Object value =
+                extension.descriptor.getEnumType().findValueByNumber(rawValue);
+            if (value == null) {
+              // If the number isn't recognized as a valid value for this
+              // enum, drop it (don't even add it to unknownFields).
+              return true;
+            }
+            extensions.addRepeatedField(extension.descriptor, value);
+          }
+        } else {
+          while (input.getBytesUntilLimit() > 0) {
+            final Object value =
+              FieldSet.readPrimitiveField(input,
+                                          extension.descriptor.getLiteType());
+            extensions.addRepeatedField(extension.descriptor, value);
+          }
+        }
+        input.popLimit(limit);
+      } else {
+        final Object value;
+        switch (extension.descriptor.getLiteJavaType()) {
+          case MESSAGE: {
+            MessageLite.Builder subBuilder = null;
+            if (!extension.descriptor.isRepeated()) {
+              MessageLite existingValue =
+                  (MessageLite) extensions.getField(extension.descriptor);
+              if (existingValue != null) {
+                subBuilder = existingValue.toBuilder();
+              }
+            }
+            if (subBuilder == null) {
+              subBuilder = extension.messageDefaultInstance.newBuilderForType();
+            }
+            if (extension.descriptor.getLiteType() ==
+                WireFormat.FieldType.GROUP) {
+              input.readGroup(extension.getNumber(),
+                              subBuilder, extensionRegistry);
+            } else {
+              input.readMessage(subBuilder, extensionRegistry);
+            }
+            value = subBuilder.build();
+            break;
+          }
+          case ENUM:
+            final int rawValue = input.readEnum();
+            value = extension.descriptor.getEnumType()
+                             .findValueByNumber(rawValue);
+            // If the number isn't recognized as a valid value for this enum,
+            // drop it.
+            if (value == null) {
+              return true;
+            }
+            break;
+          default:
+            value = FieldSet.readPrimitiveField(input,
+                extension.descriptor.getLiteType());
+            break;
+        }
+
+        if (extension.descriptor.isRepeated()) {
+          extensions.addRepeatedField(extension.descriptor, value);
+        } else {
+          extensions.setField(extension.descriptor, value);
+        }
+      }
+
+      return true;
+    }
+
+    protected final void mergeExtensionFields(final MessageType other) {
+      internalGetResult().extensions.mergeFrom(other.extensions);
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /** For use by generated code only. */
+  public static <ContainingType extends MessageLite, Type>
+      GeneratedExtension<ContainingType, Type>
+      newGeneratedExtension(
+        final ContainingType containingTypeDefaultInstance,
+        final Type defaultValue,
+        final MessageLite messageDefaultInstance,
+        final Internal.EnumLiteMap<?> enumTypeMap,
+        final int number,
+        final WireFormat.FieldType type) {
+    return new GeneratedExtension<ContainingType, Type>(
+      containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
+      new ExtensionDescriptor(enumTypeMap, number, type,
+        false /* isRepeated */, false /* isPacked */));
+  }
+
+  /** For use by generated code only. */
+  public static <ContainingType extends MessageLite, Type>
+      GeneratedExtension<ContainingType, List<Type>>
+      newRepeatedGeneratedExtension(
+        final ContainingType containingTypeDefaultInstance,
+        final MessageLite messageDefaultInstance,
+        final Internal.EnumLiteMap<?> enumTypeMap,
+        final int number,
+        final WireFormat.FieldType type,
+        final boolean isPacked) {
+    return new GeneratedExtension<ContainingType, List<Type>>(
+      containingTypeDefaultInstance, Collections.<Type>emptyList(),
+      messageDefaultInstance,
+      new ExtensionDescriptor(
+        enumTypeMap, number, type, true /* isRepeated */, isPacked));
+  }
+
+  private static final class ExtensionDescriptor
+      implements FieldSet.FieldDescriptorLite<
+        ExtensionDescriptor> {
+    private ExtensionDescriptor(
+        final Internal.EnumLiteMap<?> enumTypeMap,
+        final int number,
+        final WireFormat.FieldType type,
+        final boolean isRepeated,
+        final boolean isPacked) {
+      this.enumTypeMap = enumTypeMap;
+      this.number = number;
+      this.type = type;
+      this.isRepeated = isRepeated;
+      this.isPacked = isPacked;
+    }
+
+    private final Internal.EnumLiteMap<?> enumTypeMap;
+    private final int number;
+    private final WireFormat.FieldType type;
+    private final boolean isRepeated;
+    private final boolean isPacked;
+
+    public int getNumber() {
+      return number;
+    }
+
+    public WireFormat.FieldType getLiteType() {
+      return type;
+    }
+
+    public WireFormat.JavaType getLiteJavaType() {
+      return type.getJavaType();
+    }
+
+    public boolean isRepeated() {
+      return isRepeated;
+    }
+
+    public boolean isPacked() {
+      return isPacked;
+    }
+
+    public Internal.EnumLiteMap<?> getEnumType() {
+      return enumTypeMap;
+    }
+
+    @SuppressWarnings("unchecked")
+    public MessageLite.Builder internalMergeFrom(
+        MessageLite.Builder to, MessageLite from) {
+      return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
+    }
+
+    public int compareTo(ExtensionDescriptor other) {
+      return number - other.number;
+    }
+  }
+
+  /**
+   * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
+   *
+   * Users should ignore the contents of this class and only use objects of
+   * this type as parameters to extension accessors and ExtensionRegistry.add().
+   */
+  public static final class GeneratedExtension<
+      ContainingType extends MessageLite, Type> {
+    private GeneratedExtension(
+        final ContainingType containingTypeDefaultInstance,
+        final Type defaultValue,
+        final MessageLite messageDefaultInstance,
+        final ExtensionDescriptor descriptor) {
+      this.containingTypeDefaultInstance = containingTypeDefaultInstance;
+      this.defaultValue = defaultValue;
+      this.messageDefaultInstance = messageDefaultInstance;
+      this.descriptor = descriptor;
+    }
+
+    private final ContainingType containingTypeDefaultInstance;
+    private final Type defaultValue;
+    private final MessageLite messageDefaultInstance;
+    private final ExtensionDescriptor descriptor;
+
+    /**
+     * Default instance of the type being extended, used to identify that type.
+     */
+    public ContainingType getContainingTypeDefaultInstance() {
+      return containingTypeDefaultInstance;
+    }
+
+    /** Get the field number. */
+    public int getNumber() {
+      return descriptor.getNumber();
+    }
+
+    /**
+     * If the extension is an embedded message, this is the default instance of
+     * that type.
+     */
+    public MessageLite getMessageDefaultInstance() {
+      return messageDefaultInstance;
+    }
+  }
+}

+ 194 - 0
java/src/main/java/com/google/protobuf/Internal.java

@@ -0,0 +1,194 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * The classes contained within are used internally by the Protocol Buffer
+ * library and generated message implementations. They are public only because
+ * those generated messages do not reside in the {@code protobuf} package.
+ * Others should not use this class directly.
+ *
+ * @author cyrusn@google.com (Cyrus Najmabadi)
+ */
+public class Internal {
+  /**
+   * Implementation of a Queue designed to have as little overhead as possible.
+   * No guarantees are made as to the order you will get values back from the
+   * queue. Currently it is a Last-In-First-Out implementation, but that may
+   * change in the future.
+   *
+   * Duplicate values are allowed, as are null values.
+   *
+   * Not threadsafe.
+   *
+   * @author cyrusn@google.com (Cyrus Najmabadi)
+   */
+  public static final class QuickQueue<T> {
+    @SuppressWarnings("unchecked")
+    private T[] array = (T[]) new Object[16];
+    private int size;
+
+    /**
+     * Adds a value to the queue.
+     *
+     * @param value The value to add to the queue.
+     */
+    public void offer(final T value) {
+      if (size == array.length) {
+        // I'd like to use Arrays.copy here. However, it is currently
+        // unavailable
+        // on android. So, for now, we just use the tried and true arraycopy
+        // technique.
+        @SuppressWarnings("unchecked")
+        final T[] copy = (T[]) new Object[size * 2];
+        System.arraycopy(array, 0, copy, 0, array.length);
+        array = copy;
+      }
+
+      array[size++] = value;
+    }
+
+    /**
+     * Removes some previously added value to the queue, or {@code null} if the
+     * queue is empty.
+     *
+     * @return An existing value in the queue, or {@code null} if the queue is
+     *         empty.
+     */
+    public T poll() {
+      if (size == 0) {
+        return null;
+      }
+
+      final T result = array[--size];
+      // make sure we null out the entry so that we're not keeping anything
+      // alive unnecessarily.
+      array[size] = null;
+
+      return result;
+    }
+  }
+
+  /**
+   * Instances of this class will provide a unique {@code QuickQueue} to each
+   * thread that accesses it. Very useful for providing free lists without
+   * needing to take any locks.
+   *
+   * @author cyrusn@google.com (Cyrus Najmabadi)
+   */
+  public static final class ThreadLocalQuickQueue<T>
+      extends ThreadLocal<QuickQueue<T>> {
+    @Override
+    protected QuickQueue<T> initialValue() {
+      return new QuickQueue<T>();
+    }
+  }
+
+  /**
+   * Helper called by generated code to construct default values for string
+   * fields.
+   * <p>
+   * The protocol compiler does not actually contain a UTF-8 decoder -- it
+   * just pushes UTF-8-encoded text around without touching it.  The one place
+   * where this presents a problem is when generating Java string literals.
+   * Unicode characters in the string literal would normally need to be encoded
+   * using a Unicode escape sequence, which would require decoding them.
+   * To get around this, protoc instead embeds the UTF-8 bytes into the
+   * generated code and leaves it to the runtime library to decode them.
+   * <p>
+   * It gets worse, though.  If protoc just generated a byte array, like:
+   *   new byte[] {0x12, 0x34, 0x56, 0x78}
+   * Java actually generates *code* which allocates an array and then fills
+   * in each value.  This is much less efficient than just embedding the bytes
+   * directly into the bytecode.  To get around this, we need another
+   * work-around.  String literals are embedded directly, so protoc actually
+   * generates a string literal corresponding to the bytes.  The easiest way
+   * to do this is to use the ISO-8859-1 character set, which corresponds to
+   * the first 256 characters of the Unicode range.  Protoc can then use
+   * good old CEscape to generate the string.
+   * <p>
+   * So we have a string literal which represents a set of bytes which
+   * represents another string.  This function -- stringDefaultValue --
+   * converts from the generated string to the string we actually want.  The
+   * generated code calls this automatically.
+   */
+  public static String stringDefaultValue(String bytes) {
+    try {
+      return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      // This should never happen since all JVMs are required to implement
+      // both of the above character sets.
+      throw new IllegalStateException(
+          "Java VM does not support a standard character set.", e);
+    }
+  }
+
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+   * In this case we only need the second of the two hacks -- allowing us to
+   * embed raw bytes as a string literal with ISO-8859-1 encoding.
+   */
+  public static ByteString bytesDefaultValue(String bytes) {
+    try {
+      return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
+    } catch (UnsupportedEncodingException e) {
+      // This should never happen since all JVMs are required to implement
+      // ISO-8859-1.
+      throw new IllegalStateException(
+          "Java VM does not support a standard character set.", e);
+    }
+  }
+
+  /**
+   * Interface for an enum value or value descriptor, to be used in FieldSet.
+   * The lite library stores enum values directly in FieldSets but the full
+   * library stores EnumValueDescriptors in order to better support reflection.
+   */
+  public interface EnumLite {
+    int getNumber();
+  }
+
+  /**
+   * Interface for an object which maps integers to {@link EnumLite}s.
+   * {@link Descriptors.EnumDescriptor} implements this interface by mapping
+   * numbers to {@link Descriptors.EnumValueDescriptor}s.  Additionally,
+   * every generated enum type has a static method internalGetValueMap() which
+   * returns an implementation of this type that maps numbers to enum values.
+   */
+  public interface EnumLiteMap<T extends EnumLite> {
+    T findValueByNumber(int number);
+  }
+}

+ 3 - 1
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java

@@ -39,7 +39,9 @@ import java.io.IOException;
  * @author kenton@google.com Kenton Varda
  */
 public class InvalidProtocolBufferException extends IOException {
-  public InvalidProtocolBufferException(String description) {
+  private static final long serialVersionUID = -1616151763072450476L;
+
+  public InvalidProtocolBufferException(final String description) {
     super(description);
   }
 

+ 31 - 216
java/src/main/java/com/google/protobuf/Message.java

@@ -33,17 +33,22 @@
 
 package com.google.protobuf;
 
-import java.io.InputStream;
 import java.io.IOException;
-import java.io.OutputStream;
+import java.io.InputStream;
 import java.util.Map;
 
 /**
  * Abstract interface implemented by Protocol Message objects.
+ * <p>
+ * See also {@link MessageLite}, which defines most of the methods that typical
+ * users care about.  {@link Message} adds to it methods that are not available
+ * in the "lite" runtime.  The biggest added features are introspection and
+ * reflection -- i.e., getting descriptors for the message type and accessing
+ * the field values dynamically.
  *
  * @author kenton@google.com Kenton Varda
  */
-public interface Message {
+public interface Message extends MessageLite {
   /**
    * Get the message's type's descriptor.  This differs from the
    * {@code getDescriptor()} method of generated message classes in that
@@ -53,14 +58,7 @@ public interface Message {
    */
   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.
-   */
+  // (From MessageLite, re-declared here only for return type covariance.)
   Message getDefaultInstanceForType();
 
   /**
@@ -114,24 +112,6 @@ public interface Message {
   /** 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
 
@@ -144,6 +124,7 @@ public interface Message {
    * @param other object to be compared for equality with this message
    * @return <tt>true</tt> if the specified object is equal to this message
    */
+  @Override
   boolean equals(Object other);
 
   /**
@@ -154,6 +135,7 @@ public interface Message {
    * @return the hash code value for this message
    * @see Map#hashCode()
    */
+  @Override
   int hashCode();
 
   // -----------------------------------------------------------------
@@ -163,67 +145,22 @@ public interface Message {
    * Converts the message to a string in protocol buffer text format. This is
    * just a trivial wrapper around {@link TextFormat#printToString(Message)}.
    */
+  @Override
   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.
-   * <p>
-   * NOTE:  Protocol Buffers are not self-delimiting.  Therefore, if you write
-   * any more data to the stream after the message, you must somehow ensure
-   * that the parser on the receiving end does not interpret this as being
-   * part of the protocol message.  This can be done e.g. by writing the size
-   * of the message before the data, then making sure to limit the input to
-   * that size on the receiving end (e.g. by wrapping the InputStream in one
-   * which limits the input).  Alternatively, just use
-   * {@link #writeDelimitedTo(OutputStream)}.
-   */
-  void writeTo(OutputStream output) throws IOException;
-
-  /**
-   * Like {@link #writeTo(OutputStream)}, but writes the size of the message
-   * as a varint before writing the data.  This allows more data to be written
-   * to the stream after the message without the need to delimit the message
-   * data yourself.  Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
-   * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
-   * to parse messages written by this method.
-   */
-  void writeDelimitedTo(OutputStream output) throws IOException;
-
   // =================================================================
   // Builders
 
-  /**
-   * Constructs a new builder for a message of the same type as this message.
-   */
+  // (From MessageLite, re-declared here only for return type covariance.)
   Builder newBuilderForType();
-
-  /**
-   * Constructs a builder initialized with the current message.  Use this to
-   * derive a new message from the current one.
-   */
   Builder toBuilder();
 
   /**
    * Abstract interface implemented by Protocol Message builders.
    */
-  public static interface Builder extends Cloneable {
-    /** Resets all fields to their default values. */
+  interface Builder extends MessageLite.Builder {
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
     Builder clear();
 
     /**
@@ -244,71 +181,14 @@ public interface Message {
      */
     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.
-     */
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
     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)
+                      ExtensionRegistryLite extensionRegistry)
                       throws IOException;
 
     /**
@@ -317,10 +197,8 @@ public interface Message {
      */
     Descriptors.Descriptor getDescriptorForType();
 
-    /**
-     * Get the message's type's default instance.
-     * See {@link Message#getDefaultInstanceForType()}.
-     */
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
     Message getDefaultInstanceForType();
 
     /**
@@ -399,92 +277,29 @@ public interface Message {
     // ---------------------------------------------------------------
     // 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)}.
-     */
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
     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)
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+    Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+    Builder mergeFrom(byte[] data, int off, int len)
                       throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     */
-    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)}.
-     */
-    public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
-     */
     Builder mergeFrom(byte[] data,
-                      ExtensionRegistry extensionRegistry)
+                      ExtensionRegistryLite extensionRegistry)
                       throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
-     */
     Builder mergeFrom(byte[] data, int off, int len,
-                      ExtensionRegistry extensionRegistry)
+                      ExtensionRegistryLite extensionRegistry)
                       throws InvalidProtocolBufferException;
-
-    /**
-     * Parse a message of this type from {@code input} and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.  Note that this method always
-     * reads the <i>entire</i> input (unless it throws an exception).  If you
-     * want it to stop earlier, you will need to wrap your input in some
-     * wrapper stream that limits reading.  Or, use
-     * {@link Message#writeDelimitedTo(OutputStream)} to write your message and
-     * {@link #mergeDelimitedFrom(InputStream)} to read it.
-     * <p>
-     * Despite usually reading the entire input, this does not close the stream.
-     */
     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)
+                      ExtensionRegistryLite extensionRegistry)
                       throws IOException;
-
-    /**
-     * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
-     * Instead, the size of the message (encoded as a varint) is read first,
-     * then the message data.  Use
-     * {@link Message#writeDelimitedTo(OutputStream)} to write messages in this
-     * format.
-     */
     Builder mergeDelimitedFrom(InputStream input)
                                throws IOException;
-
-    /**
-     * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
-     */
     Builder mergeDelimitedFrom(InputStream input,
-                               ExtensionRegistry extensionRegistry)
+                               ExtensionRegistryLite extensionRegistry)
                                throws IOException;
   }
 }

+ 331 - 0
java/src/main/java/com/google/protobuf/MessageLite.java

@@ -0,0 +1,331 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
+//   mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * <p>This interface is implemented by all protocol message objects.  Most
+ * users will be more interested in the Message interface, which is a subclass
+ * of MessageLite.  Use MessageLite instead when you only need the subset of
+ * features which it supports -- namely, nothing that uses descriptors or
+ * reflection.  You can instruct the protocol compiler to generate classes
+ * which implement only MessageLite, not the full Message interface, by adding
+ * the follow line to the .proto file:
+ * <pre>
+ *   option optimize_for = LITE_RUNTIME;
+ * </pre>
+ *
+ * <p>This is particularly useful on resource-constrained systems where the
+ * full protocol buffers runtime library is too big.
+ *
+ * <p>Note that on non-constrained systems (e.g. servers) when you need to link
+ * in lots of protocol definitions, a better way to reduce total code footprint
+ * is to use {@code optimize_for = CODE_SIZE}.  This will make the generated
+ * code smaller while still supporting all the same features (at the expense of
+ * speed).  {@code optimize_for = LITE_RUNTIME} is best when you only have a
+ * small number of message types linked into your binary, in which case the
+ * size of the protocol buffers runtime itself is the biggest problem.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface MessageLite {
+  /**
+   * 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 MessageLite} interface
+   * whereas {@code getDefaultInstance()} is a static method of a specific
+   * class.  They return the same thing.
+   */
+  MessageLite getDefaultInstanceForType();
+
+  /**
+   * 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();
+
+  // -----------------------------------------------------------------
+  // Convenience methods.
+
+  /**
+   * Serializes the message to a {@code ByteString} and returns it. This is
+   * just a trivial wrapper around
+   * {@link #writeTo(CodedOutputStream)}.
+   */
+  ByteString toByteString();
+
+  /**
+   * Serializes the message to a {@code byte} array and returns it.  This is
+   * just a trivial wrapper around
+   * {@link #writeTo(CodedOutputStream)}.
+   */
+  byte[] toByteArray();
+
+  /**
+   * Serializes the message and writes it to {@code output}.  This is just a
+   * trivial wrapper around {@link #writeTo(CodedOutputStream)}.  This does
+   * not flush or close the stream.
+   * <p>
+   * NOTE:  Protocol Buffers are not self-delimiting.  Therefore, if you write
+   * any more data to the stream after the message, you must somehow ensure
+   * that the parser on the receiving end does not interpret this as being
+   * part of the protocol message.  This can be done e.g. by writing the size
+   * of the message before the data, then making sure to limit the input to
+   * that size on the receiving end (e.g. by wrapping the InputStream in one
+   * which limits the input).  Alternatively, just use
+   * {@link #writeDelimitedTo(OutputStream)}.
+   */
+  void writeTo(OutputStream output) throws IOException;
+
+  /**
+   * Like {@link #writeTo(OutputStream)}, but writes the size of the message
+   * as a varint before writing the data.  This allows more data to be written
+   * to the stream after the message without the need to delimit the message
+   * data yourself.  Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
+   * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
+   * to parse messages written by this method.
+   */
+  void writeDelimitedTo(OutputStream output) throws IOException;
+
+  // =================================================================
+  // Builders
+
+  /**
+   * Constructs a new builder for a message of the same type as this message.
+   */
+  Builder newBuilderForType();
+
+  /**
+   * Constructs a builder initialized with the current message.  Use this to
+   * derive a new message from the current one.
+   */
+  Builder toBuilder();
+
+  /**
+   * Abstract interface implemented by Protocol Message builders.
+   */
+  interface Builder extends Cloneable {
+    /** Resets all fields to their default values. */
+    Builder clear();
+
+    /**
+     * Construct the final message.  Once this is called, the Builder is no
+     * longer valid, and calling any other method will result in undefined
+     * behavior and 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.
+     */
+    MessageLite build();
+
+    /**
+     * Like {@link #build()}, but does not throw an exception if the message
+     * is missing required fields.  Instead, a partial message is returned.
+     * Once this is called, the Builder is no longer valid, and calling any
+     * will result in undefined behavior and may throw a NullPointerException.
+     *
+     * If you need to continue working with the builder after calling
+     * {@code buildPartial()}, {@code clone()} it first.
+     */
+    MessageLite 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(MessageLite)}.
+     *
+     * <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(MessageLite)}
+     *       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,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws IOException;
+
+    /**
+     * Get the message's type's default instance.
+     * See {@link MessageLite#getDefaultInstanceForType()}.
+     */
+    MessageLite getDefaultInstanceForType();
+
+    // ---------------------------------------------------------------
+    // 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,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     */
+    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)}.
+     */
+    Builder mergeFrom(byte[] data, int off, int len)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+     */
+    Builder mergeFrom(byte[] data,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+     */
+    Builder mergeFrom(byte[] data, int off, int len,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse a message of this type from {@code input} and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.  Note that this method always
+     * reads the <i>entire</i> input (unless it throws an exception).  If you
+     * want it to stop earlier, you will need to wrap your input in some
+     * wrapper stream that limits reading.  Or, use
+     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
+     * and {@link #mergeDelimitedFrom(InputStream)} to read it.
+     * <p>
+     * Despite usually reading the entire input, this does not close the stream.
+     */
+    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,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws IOException;
+
+    /**
+     * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
+     * Instead, the size of the message (encoded as a varint) is read first,
+     * then the message data.  Use
+     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
+     * this format.
+     */
+    Builder mergeDelimitedFrom(InputStream input)
+                               throws IOException;
+
+    /**
+     * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
+     */
+    Builder mergeDelimitedFrom(InputStream input,
+                               ExtensionRegistryLite extensionRegistry)
+                               throws IOException;
+  }
+}

+ 1 - 1
java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java

@@ -37,7 +37,7 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
  * Interface of useful methods added to all enums generated by the protocol
  * compiler.
  */
-public interface ProtocolMessageEnum {
+public interface ProtocolMessageEnum extends Internal.EnumLite {
 
   /**
    * Return the value's numeric value as defined in the .proto file.

+ 8 - 5
java/src/main/java/com/google/protobuf/RpcUtil.java

@@ -71,11 +71,11 @@ public final class RpcUtil {
       final Class<Type> originalClass,
       final Type defaultInstance) {
     return new RpcCallback<Message>() {
-      public void run(Message parameter) {
+      public void run(final Message parameter) {
         Type typedParameter;
         try {
           typedParameter = originalClass.cast(parameter);
-        } catch (ClassCastException e) {
+        } catch (ClassCastException ignored) {
           typedParameter = copyAsType(defaultInstance, parameter);
         }
         originalCallback.run(typedParameter);
@@ -90,7 +90,7 @@ public final class RpcUtil {
    */
   @SuppressWarnings("unchecked")
   private static <Type extends Message> Type copyAsType(
-      Type typeDefaultInstance, Message source) {
+      final Type typeDefaultInstance, final Message source) {
     return (Type)typeDefaultInstance.newBuilderForType()
                                     .mergeFrom(source)
                                     .build();
@@ -106,8 +106,9 @@ public final class RpcUtil {
     RpcCallback<ParameterType> newOneTimeCallback(
       final RpcCallback<ParameterType> originalCallback) {
     return new RpcCallback<ParameterType>() {
-      boolean alreadyCalled = false;
-      public void run(ParameterType parameter) {
+      private boolean alreadyCalled = false;
+
+      public void run(final ParameterType parameter) {
         synchronized(this) {
           if (alreadyCalled) {
             throw new AlreadyCalledException();
@@ -124,6 +125,8 @@ public final class RpcUtil {
    * Exception thrown when a one-time callback is called more than once.
    */
   public static final class AlreadyCalledException extends RuntimeException {
+    private static final long serialVersionUID = 5469741279507848266L;
+
     public AlreadyCalledException() {
       super("This RpcCallback was already called and cannot be called " +
             "multiple times.");

+ 4 - 2
java/src/main/java/com/google/protobuf/ServiceException.java

@@ -32,11 +32,13 @@ package com.google.protobuf;
 
 /**
  * Thrown by blocking RPC methods when a failure occurs.
- * 
+ *
  * @author cpovirk@google.com (Chris Povirk)
  */
 public final class ServiceException extends Exception {
-  public ServiceException(String message) {
+  private static final long serialVersionUID = -1219262335729891920L;
+
+  public ServiceException(final String message) {
     super(message);
   }
 }

+ 164 - 132
java/src/main/java/com/google/protobuf/TextFormat.java

@@ -52,22 +52,25 @@ import java.util.regex.Pattern;
  * @author kenton@google.com Kenton Varda
  */
 public final class TextFormat {
+  private 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)
+  public static void print(final Message message, final Appendable output)
                            throws IOException {
-    TextGenerator generator = new TextGenerator(output);
+    final 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)
+  public static void print(final UnknownFieldSet fields,
+                           final Appendable output)
                            throws IOException {
-    TextGenerator generator = new TextGenerator(output);
+    final TextGenerator generator = new TextGenerator(output);
     printUnknownFields(fields, generator);
   }
 
@@ -75,9 +78,9 @@ public final class TextFormat {
    * Like {@code print()}, but writes directly to a {@code String} and
    * returns it.
    */
-  public static String printToString(Message message) {
+  public static String printToString(final Message message) {
     try {
-      StringBuilder text = new StringBuilder();
+      final StringBuilder text = new StringBuilder();
       print(message, text);
       return text.toString();
     } catch (IOException e) {
@@ -91,9 +94,9 @@ public final class TextFormat {
    * Like {@code print()}, but writes directly to a {@code String} and
    * returns it.
    */
-  public static String printToString(UnknownFieldSet fields) {
+  public static String printToString(final UnknownFieldSet fields) {
     try {
-      StringBuilder text = new StringBuilder();
+      final StringBuilder text = new StringBuilder();
       print(fields, text);
       return text.toString();
     } catch (IOException e) {
@@ -103,22 +106,44 @@ public final class TextFormat {
     }
   }
 
-  private static void print(Message message, TextGenerator generator)
+  private static void print(final Message message,
+                            final TextGenerator generator)
       throws IOException {
-    for (Map.Entry<FieldDescriptor, Object> field :
+    for (final Map.Entry<FieldDescriptor, Object> field :
          message.getAllFields().entrySet()) {
       printField(field.getKey(), field.getValue(), generator);
     }
     printUnknownFields(message.getUnknownFields(), generator);
   }
+  
+  public static void printField(final FieldDescriptor field,
+                                final Object value,
+                                final Appendable output)
+                                throws IOException {
+    final TextGenerator generator = new TextGenerator(output);
+    printField(field, value, generator);
+  }
 
-  public static void printField(FieldDescriptor field,
-                                Object value,
-                                TextGenerator generator)
+  public static String printFieldToString(final FieldDescriptor field,
+                                          final Object value) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      printField(field, value, text);
+      return text.toString();
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Writing to a StringBuilder threw an IOException (should never " +
+        "happen).", e);  
+    }
+  }
+  
+  private static void printField(final FieldDescriptor field,
+                                final Object value,
+                                final TextGenerator generator)
                                 throws IOException {
     if (field.isRepeated()) {
       // Repeated field.  Print each element.
-      for (Object element : (List) value) {
+      for (final Object element : (List) value) {
         printSingleField(field, element, generator);
       }
     } else {
@@ -126,9 +151,9 @@ public final class TextFormat {
     }
   }
 
-  private static void printSingleField(FieldDescriptor field,
-                                       Object value,
-                                       TextGenerator generator)
+  private static void printSingleField(final FieldDescriptor field,
+                                       final Object value,
+                                       final TextGenerator generator)
                                        throws IOException {
     if (field.isExtension()) {
       generator.print("[");
@@ -168,9 +193,9 @@ public final class TextFormat {
     generator.print("\n");
   }
 
-  private static void printFieldValue(FieldDescriptor field,
-                                      Object value,
-                                      TextGenerator generator)
+  private static void printFieldValue(final FieldDescriptor field,
+                                      final Object value,
+                                      final TextGenerator generator)
                                       throws IOException {
     switch (field.getType()) {
       case INT32:
@@ -202,17 +227,15 @@ public final class TextFormat {
         generator.print("\"");
         break;
 
-      case BYTES: {
+      case BYTES:
         generator.print("\"");
         generator.print(escapeBytes((ByteString) value));
         generator.print("\"");
         break;
-      }
 
-      case ENUM: {
+      case ENUM:
         generator.print(((EnumValueDescriptor) value).getName());
         break;
-      }
 
       case MESSAGE:
       case GROUP:
@@ -221,39 +244,39 @@ public final class TextFormat {
     }
   }
 
-  private static void printUnknownFields(UnknownFieldSet unknownFields,
-                                         TextGenerator generator)
+  private static void printUnknownFields(final UnknownFieldSet unknownFields,
+                                         final TextGenerator generator)
                                          throws IOException {
-    for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+    for (final Map.Entry<Integer, UnknownFieldSet.Field> entry :
          unknownFields.asMap().entrySet()) {
-      String prefix = entry.getKey().toString() + ": ";
-      UnknownFieldSet.Field field = entry.getValue();
+      final String prefix = entry.getKey().toString() + ": ";
+      final UnknownFieldSet.Field field = entry.getValue();
 
-      for (long value : field.getVarintList()) {
+      for (final long value : field.getVarintList()) {
         generator.print(entry.getKey().toString());
         generator.print(": ");
         generator.print(unsignedToString(value));
         generator.print("\n");
       }
-      for (int value : field.getFixed32List()) {
+      for (final 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()) {
+      for (final 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()) {
+      for (final ByteString value : field.getLengthDelimitedList()) {
         generator.print(entry.getKey().toString());
         generator.print(": \"");
         generator.print(escapeBytes(value));
         generator.print("\"\n");
       }
-      for (UnknownFieldSet value : field.getGroupList()) {
+      for (final UnknownFieldSet value : field.getGroupList()) {
         generator.print(entry.getKey().toString());
         generator.print(" {\n");
         generator.indent();
@@ -265,7 +288,7 @@ public final class TextFormat {
   }
 
   /** Convert an unsigned 32-bit integer to a string. */
-  private static String unsignedToString(int value) {
+  private static String unsignedToString(final int value) {
     if (value >= 0) {
       return Integer.toString(value);
     } else {
@@ -274,7 +297,7 @@ public final class TextFormat {
   }
 
   /** Convert an unsigned 64-bit integer to a string. */
-  private static String unsignedToString(long value) {
+  private static String unsignedToString(final long value) {
     if (value >= 0) {
       return Long.toString(value);
     } else {
@@ -288,13 +311,12 @@ public final class TextFormat {
   /**
    * An inner class for writing text to the output stream.
    */
-  static private final class TextGenerator {
+  private static final class TextGenerator {
+    private Appendable output;
+    private boolean atStartOfLine = true;
+    private final StringBuilder indent = new StringBuilder();
 
-    Appendable output;
-    boolean atStartOfLine = true;
-    StringBuilder indent = new StringBuilder();
-
-    public TextGenerator(Appendable output) {
+    private TextGenerator(final Appendable output) {
       this.output = output;
     }
 
@@ -312,7 +334,7 @@ public final class TextFormat {
      * level is zero.
      */
     public void outdent() {
-      int length = indent.length();
+      final int length = indent.length();
       if (length == 0) {
         throw new IllegalArgumentException(
             " Outdent() without matching Indent().");
@@ -323,8 +345,8 @@ public final class TextFormat {
     /**
      * Print text to the output stream.
      */
-    public void print(CharSequence text) throws IOException {
-      int size = text.length();
+    public void print(final CharSequence text) throws IOException {
+      final int size = text.length();
       int pos = 0;
 
       for (int i = 0; i < size; i++) {
@@ -337,7 +359,8 @@ public final class TextFormat {
       write(text.subSequence(pos, size), size - pos);
     }
 
-    private void write(CharSequence data, int size) throws IOException {
+    private void write(final CharSequence data, final int size)
+                       throws IOException {
       if (size == 0) {
         return;
       }
@@ -399,27 +422,27 @@ public final class TextFormat {
 
     // We use possesive quantifiers (*+ and ++) because otherwise the Java
     // regex matcher has stack overflows on large inputs.
-    private static Pattern WHITESPACE =
+    private static final Pattern WHITESPACE =
       Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
-    private static Pattern TOKEN = Pattern.compile(
+    private static final Pattern TOKEN = Pattern.compile(
       "[a-zA-Z_][0-9a-zA-Z_+-]*+|" +                // an identifier
       "[0-9+-][0-9a-zA-Z_.+-]*+|" +                 // a number
       "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" +       // a double-quoted string
       "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)",         // a single-quoted string
       Pattern.MULTILINE);
 
-    private static Pattern DOUBLE_INFINITY = Pattern.compile(
+    private static final Pattern DOUBLE_INFINITY = Pattern.compile(
       "-?inf(inity)?",
       Pattern.CASE_INSENSITIVE);
-    private static Pattern FLOAT_INFINITY = Pattern.compile(
+    private static final Pattern FLOAT_INFINITY = Pattern.compile(
       "-?inf(inity)?f?",
       Pattern.CASE_INSENSITIVE);
-    private static Pattern FLOAT_NAN = Pattern.compile(
+    private static final Pattern FLOAT_NAN = Pattern.compile(
       "nanf?",
       Pattern.CASE_INSENSITIVE);
 
     /** Construct a tokenizer that parses tokens from the given text. */
-    public Tokenizer(CharSequence text) {
+    private Tokenizer(final CharSequence text) {
       this.text = text;
       this.matcher = WHITESPACE.matcher(text);
       skipWhitespace();
@@ -481,7 +504,7 @@ public final class TextFormat {
      * 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) {
+    public boolean tryConsume(final String token) {
       if (currentToken.equals(token)) {
         nextToken();
         return true;
@@ -494,7 +517,7 @@ public final class TextFormat {
      * If the next token exactly matches {@code token}, consume it.  Otherwise,
      * throw a {@link ParseException}.
      */
-    public void consume(String token) throws ParseException {
+    public void consume(final String token) throws ParseException {
       if (!tryConsume(token)) {
         throw parseException("Expected \"" + token + "\".");
       }
@@ -509,7 +532,7 @@ public final class TextFormat {
         return false;
       }
 
-      char c = currentToken.charAt(0);
+      final char c = currentToken.charAt(0);
       return ('0' <= c && c <= '9') ||
              c == '-' || c == '+';
     }
@@ -520,7 +543,7 @@ public final class TextFormat {
      */
     public String consumeIdentifier() throws ParseException {
       for (int i = 0; i < currentToken.length(); i++) {
-        char c = currentToken.charAt(i);
+        final char c = currentToken.charAt(i);
         if (('a' <= c && c <= 'z') ||
             ('A' <= c && c <= 'Z') ||
             ('0' <= c && c <= '9') ||
@@ -531,7 +554,7 @@ public final class TextFormat {
         }
       }
 
-      String result = currentToken;
+      final String result = currentToken;
       nextToken();
       return result;
     }
@@ -542,7 +565,7 @@ public final class TextFormat {
      */
     public int consumeInt32() throws ParseException {
       try {
-        int result = parseInt32(currentToken);
+        final int result = parseInt32(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -556,7 +579,7 @@ public final class TextFormat {
      */
     public int consumeUInt32() throws ParseException {
       try {
-        int result = parseUInt32(currentToken);
+        final int result = parseUInt32(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -570,7 +593,7 @@ public final class TextFormat {
      */
     public long consumeInt64() throws ParseException {
       try {
-        long result = parseInt64(currentToken);
+        final long result = parseInt64(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -584,7 +607,7 @@ public final class TextFormat {
      */
     public long consumeUInt64() throws ParseException {
       try {
-        long result = parseUInt64(currentToken);
+        final long result = parseUInt64(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -600,7 +623,7 @@ public final class TextFormat {
       // We need to parse infinity and nan separately because
       // Double.parseDouble() does not accept "inf", "infinity", or "nan".
       if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
-        boolean negative = currentToken.startsWith("-");
+        final boolean negative = currentToken.startsWith("-");
         nextToken();
         return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
       }
@@ -609,7 +632,7 @@ public final class TextFormat {
         return Double.NaN;
       }
       try {
-        double result = Double.parseDouble(currentToken);
+        final double result = Double.parseDouble(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -625,7 +648,7 @@ public final class TextFormat {
       // We need to parse infinity and nan separately because
       // Float.parseFloat() does not accept "inf", "infinity", or "nan".
       if (FLOAT_INFINITY.matcher(currentToken).matches()) {
-        boolean negative = currentToken.startsWith("-");
+        final boolean negative = currentToken.startsWith("-");
         nextToken();
         return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
       }
@@ -634,7 +657,7 @@ public final class TextFormat {
         return Float.NaN;
       }
       try {
-        float result = Float.parseFloat(currentToken);
+        final float result = Float.parseFloat(currentToken);
         nextToken();
         return result;
       } catch (NumberFormatException e) {
@@ -672,7 +695,8 @@ public final class TextFormat {
      * {@link ParseException}.
      */
     public ByteString consumeByteString() throws ParseException {
-      char quote = currentToken.length() > 0 ? currentToken.charAt(0) : '\0';
+      final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
+                                                   : '\0';
       if (quote != '\"' && quote != '\'') {
         throw parseException("Expected string.");
       }
@@ -683,11 +707,12 @@ public final class TextFormat {
       }
 
       try {
-        String escaped = currentToken.substring(1, currentToken.length() - 1);
-        ByteString result = unescapeBytes(escaped);
+        final String escaped =
+            currentToken.substring(1, currentToken.length() - 1);
+        final ByteString result = unescapeBytes(escaped);
         nextToken();
         return result;
-      } catch (InvalidEscapeSequence e) {
+      } catch (InvalidEscapeSequenceException e) {
         throw parseException(e.getMessage());
       }
     }
@@ -696,7 +721,7 @@ public final class TextFormat {
      * Returns a {@link ParseException} with the current line and column
      * numbers in the description, suitable for throwing.
      */
-    public ParseException parseException(String description) {
+    public ParseException parseException(final String description) {
       // Note:  People generally prefer one-based line and column numbers.
       return new ParseException(
         (line + 1) + ":" + (column + 1) + ": " + description);
@@ -706,7 +731,8 @@ public final class TextFormat {
      * 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) {
+    public ParseException parseExceptionPreviousToken(
+        final String description) {
       // Note:  People generally prefer one-based line and column numbers.
       return new ParseException(
         (previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
@@ -716,7 +742,8 @@ public final class TextFormat {
      * Constructs an appropriate {@link ParseException} for the given
      * {@code NumberFormatException} when trying to parse an integer.
      */
-    private ParseException integerParseException(NumberFormatException e) {
+    private ParseException integerParseException(
+        final NumberFormatException e) {
       return parseException("Couldn't parse integer: " + e.getMessage());
     }
 
@@ -724,14 +751,16 @@ public final class TextFormat {
      * Constructs an appropriate {@link ParseException} for the given
      * {@code NumberFormatException} when trying to parse a float or double.
      */
-    private ParseException floatParseException(NumberFormatException e) {
+    private ParseException floatParseException(final NumberFormatException e) {
       return parseException("Couldn't parse number: " + e.getMessage());
     }
   }
 
   /** Thrown when parsing an invalid text format message. */
   public static class ParseException extends IOException {
-    public ParseException(String message) {
+    private static final long serialVersionUID = 3196188060225107702L;
+
+    public ParseException(final String message) {
       super(message);
     }
   }
@@ -740,9 +769,9 @@ public final class TextFormat {
    * 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 {
+  public static void merge(final Readable input,
+                           final Message.Builder builder)
+                           throws IOException {
     merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
   }
 
@@ -750,8 +779,8 @@ public final class TextFormat {
    * Parse a text-format message from {@code input} and merge the contents
    * into {@code builder}.
    */
-  public static void merge(CharSequence input,
-                           Message.Builder builder)
+  public static void merge(final CharSequence input,
+                           final Message.Builder builder)
                            throws ParseException {
     merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
   }
@@ -761,10 +790,10 @@ public final class TextFormat {
    * 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 {
+  public static void merge(final Readable input,
+                           final ExtensionRegistry extensionRegistry,
+                           final Message.Builder builder)
+                           throws IOException {
     // Read the entire input to a String then parse that.
 
     // If StreamTokenizer were not quite so crippled, or if there were a kind
@@ -780,12 +809,12 @@ public final class TextFormat {
 
   // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
   // overhead is worthwhile
-  private static StringBuilder toStringBuilder(Readable input)
+  private static StringBuilder toStringBuilder(final Readable input)
       throws IOException {
-    StringBuilder text = new StringBuilder();
-    CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
+    final StringBuilder text = new StringBuilder();
+    final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
     while (true) {
-      int n = input.read(buffer);
+      final int n = input.read(buffer);
       if (n == -1) {
         break;
       }
@@ -800,11 +829,11 @@ public final class TextFormat {
    * 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)
+  public static void merge(final CharSequence input,
+                           final ExtensionRegistry extensionRegistry,
+                           final Message.Builder builder)
                            throws ParseException {
-    Tokenizer tokenizer = new Tokenizer(input);
+    final Tokenizer tokenizer = new Tokenizer(input);
 
     while (!tokenizer.atEnd()) {
       mergeField(tokenizer, extensionRegistry, builder);
@@ -815,19 +844,20 @@ public final class TextFormat {
    * Parse a single field from {@code tokenizer} and merge it into
    * {@code builder}.
    */
-  private static void mergeField(Tokenizer tokenizer,
-                                 ExtensionRegistry extensionRegistry,
-                                 Message.Builder builder)
+  private static void mergeField(final Tokenizer tokenizer,
+                                 final ExtensionRegistry extensionRegistry,
+                                 final Message.Builder builder)
                                  throws ParseException {
     FieldDescriptor field;
-    Descriptor type = builder.getDescriptorForType();
+    final Descriptor type = builder.getDescriptorForType();
     ExtensionRegistry.ExtensionInfo extension = null;
 
     if (tokenizer.tryConsume("[")) {
       // An extension.
-      StringBuilder name = new StringBuilder(tokenizer.consumeIdentifier());
+      final StringBuilder name =
+          new StringBuilder(tokenizer.consumeIdentifier());
       while (tokenizer.tryConsume(".")) {
-        name.append(".");
+        name.append('.');
         name.append(tokenizer.consumeIdentifier());
       }
 
@@ -846,7 +876,7 @@ public final class TextFormat {
 
       field = extension.descriptor;
     } else {
-      String name = tokenizer.consumeIdentifier();
+      final String name = tokenizer.consumeIdentifier();
       field = type.findFieldByName(name);
 
       // Group names are expected to be capitalized as they appear in the
@@ -855,7 +885,7 @@ public final class TextFormat {
       if (field == null) {
         // Explicitly specify US locale so that this code does not break when
         // executing in Turkey.
-        String lowerName = name.toLowerCase(Locale.US);
+        final String lowerName = name.toLowerCase(Locale.US);
         field = type.findFieldByName(lowerName);
         // If the case-insensitive match worked but the field is NOT a group,
         if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
@@ -880,7 +910,7 @@ public final class TextFormat {
     if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
       tokenizer.tryConsume(":");  // optional
 
-      String endToken;
+      final String endToken;
       if (tokenizer.tryConsume("<")) {
         endToken = ">";
       } else {
@@ -888,7 +918,7 @@ public final class TextFormat {
         endToken = "}";
       }
 
-      Message.Builder subBuilder;
+      final Message.Builder subBuilder;
       if (extension == null) {
         subBuilder = builder.newBuilderForField(field);
       } else {
@@ -951,19 +981,19 @@ public final class TextFormat {
           value = tokenizer.consumeByteString();
           break;
 
-        case ENUM: {
-          EnumDescriptor enumType = field.getEnumType();
+        case ENUM:
+          final EnumDescriptor enumType = field.getEnumType();
 
           if (tokenizer.lookingAtInteger()) {
-            int number = tokenizer.consumeInt32();
+            final int number = tokenizer.consumeInt32();
             value = enumType.findValueByNumber(number);
             if (value == null) {
               throw tokenizer.parseExceptionPreviousToken(
                 "Enum type \"" + enumType.getFullName() +
-                "\" has no value with number " + number + ".");
+                "\" has no value with number " + number + '.');
             }
           } else {
-            String id = tokenizer.consumeIdentifier();
+            final String id = tokenizer.consumeIdentifier();
             value = enumType.findValueByName(id);
             if (value == null) {
               throw tokenizer.parseExceptionPreviousToken(
@@ -973,7 +1003,6 @@ public final class TextFormat {
           }
 
           break;
-        }
 
         case MESSAGE:
         case GROUP:
@@ -1002,10 +1031,10 @@ public final class TextFormat {
    * 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());
+  static String escapeBytes(final ByteString input) {
+    final StringBuilder builder = new StringBuilder(input.size());
     for (int i = 0; i < input.size(); i++) {
-      byte b = input.byteAt(i);
+      final byte b = input.byteAt(i);
       switch (b) {
         // Java does not recognize \a or \v, apparently.
         case 0x07: builder.append("\\a" ); break;
@@ -1038,9 +1067,9 @@ public final class TextFormat {
    * {@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()];
+  static ByteString unescapeBytes(final CharSequence input)
+      throws InvalidEscapeSequenceException {
+    final byte[] result = new byte[input.length()];
     int pos = 0;
     for (int i = 0; i < input.length(); i++) {
       char c = input.charAt(i);
@@ -1080,7 +1109,7 @@ public final class TextFormat {
                   ++i;
                   code = digitValue(input.charAt(i));
                 } else {
-                  throw new InvalidEscapeSequence(
+                  throw new InvalidEscapeSequenceException(
                     "Invalid escape sequence: '\\x' with no digits");
                 }
                 if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
@@ -1091,12 +1120,12 @@ public final class TextFormat {
                 break;
 
               default:
-                throw new InvalidEscapeSequence(
-                  "Invalid escape sequence: '\\" + c + "'");
+                throw new InvalidEscapeSequenceException(
+                  "Invalid escape sequence: '\\" + c + '\'');
             }
           }
         } else {
-          throw new InvalidEscapeSequence(
+          throw new InvalidEscapeSequenceException(
             "Invalid escape sequence: '\\' at end of string.");
         }
       } else {
@@ -1111,8 +1140,10 @@ public final class TextFormat {
    * 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) {
+  static class InvalidEscapeSequenceException extends IOException {
+    private static final long serialVersionUID = -8164033650142593304L;
+
+    InvalidEscapeSequenceException(final String description) {
       super(description);
     }
   }
@@ -1122,7 +1153,7 @@ public final class TextFormat {
    * 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) {
+  static String escapeText(final String input) {
     return escapeBytes(ByteString.copyFromUtf8(input));
   }
 
@@ -1130,17 +1161,18 @@ public final class TextFormat {
    * 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 {
+  static String unescapeText(final String input)
+                             throws InvalidEscapeSequenceException {
     return unescapeBytes(input).toStringUtf8();
   }
 
   /** Is this an octal digit? */
-  private static boolean isOctal(char c) {
+  private static boolean isOctal(final char c) {
     return '0' <= c && c <= '7';
   }
 
   /** Is this a hex digit? */
-  private static boolean isHex(char c) {
+  private static boolean isHex(final char c) {
     return ('0' <= c && c <= '9') ||
            ('a' <= c && c <= 'f') ||
            ('A' <= c && c <= 'F');
@@ -1151,7 +1183,7 @@ public final class TextFormat {
    * numeric value.  This is like {@code Character.digit()} but we don't accept
    * non-ASCII digits.
    */
-  private static int digitValue(char c) {
+  private static int digitValue(final char c) {
     if ('0' <= c && c <= '9') {
       return c - '0';
     } else if ('a' <= c && c <= 'z') {
@@ -1166,7 +1198,7 @@ public final class TextFormat {
    * {@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 {
+  static int parseInt32(final String text) throws NumberFormatException {
     return (int) parseInteger(text, true, false);
   }
 
@@ -1177,7 +1209,7 @@ public final class TextFormat {
    * result is coerced to a (signed) {@code int} when returned since Java has
    * no unsigned integer type.
    */
-  static int parseUInt32(String text) throws NumberFormatException {
+  static int parseUInt32(final String text) throws NumberFormatException {
     return (int) parseInteger(text, false, false);
   }
 
@@ -1186,7 +1218,7 @@ public final class TextFormat {
    * {@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 {
+  static long parseInt64(final String text) throws NumberFormatException {
     return parseInteger(text, true, true);
   }
 
@@ -1197,13 +1229,13 @@ public final class TextFormat {
    * result is coerced to a (signed) {@code long} when returned since Java has
    * no unsigned long type.
    */
-  static long parseUInt64(String text) throws NumberFormatException {
+  static long parseUInt64(final String text) throws NumberFormatException {
     return parseInteger(text, false, true);
   }
 
-  private static long parseInteger(String text,
-                                   boolean isSigned,
-                                   boolean isLong)
+  private static long parseInteger(final String text,
+                                   final boolean isSigned,
+                                   final boolean isLong)
                                    throws NumberFormatException {
     int pos = 0;
 
@@ -1224,7 +1256,7 @@ public final class TextFormat {
       radix = 8;
     }
 
-    String numberText = text.substring(pos);
+    final String numberText = text.substring(pos);
 
     long result = 0;
     if (numberText.length() < 16) {

+ 12 - 73
java/src/main/java/com/google/protobuf/UninitializedMessageException.java

@@ -30,12 +30,8 @@
 
 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
@@ -51,11 +47,15 @@ import java.util.Map;
  * @author kenton@google.com Kenton Varda
  */
 public class UninitializedMessageException extends RuntimeException {
-  public UninitializedMessageException(Message message) {
-    this(findMissingFields(message));
+  private static final long serialVersionUID = -7466929953374883507L;
+
+  public UninitializedMessageException(final MessageLite message) {
+    super("Message was missing required fields.  (Lite runtime could not " +
+          "determine which fields were missing).");
+    missingFields = null;
   }
 
-  private UninitializedMessageException(List<String> missingFields) {
+  public UninitializedMessageException(final List<String> missingFields) {
     super(buildDescription(missingFields));
     this.missingFields = missingFields;
   }
@@ -65,6 +65,8 @@ public class UninitializedMessageException extends RuntimeException {
   /**
    * 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".
+   * Returns null if the lite runtime was used, since it lacks the ability to
+   * find missing fields.
    */
   public List<String> getMissingFields() {
     return Collections.unmodifiableList(missingFields);
@@ -80,11 +82,11 @@ public class UninitializedMessageException extends RuntimeException {
   }
 
   /** Construct the description string for this exception. */
-  private static String buildDescription(List<String> missingFields) {
-    StringBuilder description =
+  private static String buildDescription(final List<String> missingFields) {
+    final StringBuilder description =
       new StringBuilder("Message missing required fields: ");
     boolean first = true;
-    for (String field : missingFields) {
+    for (final String field : missingFields) {
       if (first) {
         first = false;
       } else {
@@ -94,67 +96,4 @@ public class UninitializedMessageException extends RuntimeException {
     }
     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();
-  }
 }

+ 274 - 115
java/src/main/java/com/google/protobuf/UnknownFieldSet.java

@@ -30,15 +30,17 @@
 
 package com.google.protobuf;
 
-import java.io.InputStream;
+import com.google.protobuf.Internal.ThreadLocalQuickQueue;
+
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.TreeMap;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 /**
  * {@code UnknownFieldSet} is used to keep track of fields which were seen when
@@ -48,56 +50,59 @@ import java.util.Map;
  * 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}).
+ * {@link Message.Builder} contains an {@link Builder}).
  *
  * <p>Most users will never need to use this class.
  *
  * @author kenton@google.com Kenton Varda
  */
-public final class UnknownFieldSet {
+public final class UnknownFieldSet implements MessageLite {
   private UnknownFieldSet() {}
 
-  /** Create a new {@link UnknownFieldSet.Builder}. */
+  /** Create a new {@link Builder}. */
   public static Builder newBuilder() {
-    return new Builder();
+    return Builder.create();
   }
 
   /**
-   * Create a new {@link UnknownFieldSet.Builder} and initialize it to be a copy
+   * Create a new {@link Builder} and initialize it to be a copy
    * of {@code copyFrom}.
    */
-  public static Builder newBuilder(UnknownFieldSet copyFrom) {
-    return new Builder().mergeFrom(copyFrom);
+  public static Builder newBuilder(final UnknownFieldSet copyFrom) {
+    return newBuilder().mergeFrom(copyFrom);
   }
 
   /** Get an empty {@code UnknownFieldSet}. */
   public static UnknownFieldSet getDefaultInstance() {
     return defaultInstance;
   }
-  private static UnknownFieldSet defaultInstance =
+  public UnknownFieldSet getDefaultInstanceForType() {
+    return defaultInstance;
+  }
+  private static final UnknownFieldSet defaultInstance =
     new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
 
   /**
    * Construct an {@code UnknownFieldSet} around the given map.  The map is
    * expected to be immutable.
    */
-  private UnknownFieldSet(Map<Integer, Field> fields) {
+  private UnknownFieldSet(final Map<Integer, Field> fields) {
     this.fields = fields;
   }
   private Map<Integer, Field> fields;
 
   @Override
-  public boolean equals(Object other) {
+  public boolean equals(final Object other) {
     if (this == other) {
       return true;
     }
     return (other instanceof UnknownFieldSet) &&
-        this.fields.equals(((UnknownFieldSet) other).fields);
+           fields.equals(((UnknownFieldSet) other).fields);
   }
 
   @Override
   public int hashCode() {
-    return this.fields.hashCode();
+    return fields.hashCode();
   }
 
   /** Get a map of fields in the set by number. */
@@ -106,7 +111,7 @@ public final class UnknownFieldSet {
   }
 
   /** Check if the given field number is present in the set. */
-  public boolean hasField(int number) {
+  public boolean hasField(final int number) {
     return fields.containsKey(number);
   }
 
@@ -114,14 +119,14 @@ public final class UnknownFieldSet {
    * 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);
+  public Field getField(final int number) {
+    final Field result = fields.get(number);
     return (result == null) ? Field.getDefaultInstance() : result;
   }
 
   /** Serializes the set and writes it to {@code output}. */
-  public void writeTo(CodedOutputStream output) throws IOException {
-    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
       entry.getValue().writeTo(entry.getKey(), output);
     }
   }
@@ -131,7 +136,8 @@ public final class UnknownFieldSet {
    * just a trivial wrapper around
    * {@link TextFormat#printToString(UnknownFieldSet)}.
    */
-  public final String toString() {
+  @Override
+  public String toString() {
     return TextFormat.printToString(this);
   }
 
@@ -139,13 +145,13 @@ public final class UnknownFieldSet {
    * Serializes the message to a {@code ByteString} and returns it. This is
    * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
    */
-  public final ByteString toByteString() {
+  public ByteString toByteString() {
     try {
-      ByteString.CodedBuilder out =
+      final ByteString.CodedBuilder out =
         ByteString.newCodedBuilder(getSerializedSize());
       writeTo(out.getCodedOutput());
       return out.build();
-    } catch (IOException e) {
+    } catch (final IOException e) {
       throw new RuntimeException(
         "Serializing to a ByteString threw an IOException (should " +
         "never happen).", e);
@@ -156,14 +162,14 @@ public final class UnknownFieldSet {
    * 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() {
+  public byte[] toByteArray() {
     try {
-      byte[] result = new byte[getSerializedSize()];
-      CodedOutputStream output = CodedOutputStream.newInstance(result);
+      final byte[] result = new byte[getSerializedSize()];
+      final CodedOutputStream output = CodedOutputStream.newInstance(result);
       writeTo(output);
       output.checkNoSpaceLeft();
       return result;
-    } catch (IOException e) {
+    } catch (final IOException e) {
       throw new RuntimeException(
         "Serializing to a byte array threw an IOException " +
         "(should never happen).", e);
@@ -174,8 +180,15 @@ public final class UnknownFieldSet {
    * 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);
+  public void writeTo(final OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  public void writeDelimitedTo(OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    codedOutput.writeRawVarint32(getSerializedSize());
     writeTo(codedOutput);
     codedOutput.flush();
   }
@@ -183,7 +196,7 @@ public final class UnknownFieldSet {
   /** Get the number of bytes required to encode this set. */
   public int getSerializedSize() {
     int result = 0;
-    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
       result += entry.getValue().getSerializedSize(entry.getKey());
     }
     return result;
@@ -193,9 +206,9 @@ public final class UnknownFieldSet {
    * Serializes the set and writes it to {@code output} using
    * {@code MessageSet} wire format.
    */
-  public void writeAsMessageSetTo(CodedOutputStream output)
+  public void writeAsMessageSetTo(final CodedOutputStream output)
       throws IOException {
-    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
       entry.getValue().writeAsMessageSetExtensionTo(
         entry.getKey(), output);
     }
@@ -207,37 +220,51 @@ public final class UnknownFieldSet {
    */
   public int getSerializedSizeAsMessageSet() {
     int result = 0;
-    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
       result += entry.getValue().getSerializedSizeAsMessageSetExtension(
         entry.getKey());
     }
     return result;
   }
 
+  public boolean isInitialized() {
+    // UnknownFieldSets do not have required fields, so they are always
+    // initialized.
+    return true;
+  }
+
   /** Parse an {@code UnknownFieldSet} from the given input stream. */
-  static public UnknownFieldSet parseFrom(CodedInputStream input)
+  public static UnknownFieldSet parseFrom(final CodedInputStream input)
                                           throws IOException {
     return newBuilder().mergeFrom(input).build();
   }
 
   /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(ByteString data)
+  public static UnknownFieldSet parseFrom(final ByteString data)
       throws InvalidProtocolBufferException {
     return newBuilder().mergeFrom(data).build();
   }
 
   /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(byte[] data)
+  public static UnknownFieldSet parseFrom(final byte[] data)
       throws InvalidProtocolBufferException {
     return newBuilder().mergeFrom(data).build();
   }
 
   /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
-  public static UnknownFieldSet parseFrom(InputStream input)
+  public static UnknownFieldSet parseFrom(final InputStream input)
                                           throws IOException {
     return newBuilder().mergeFrom(input).build();
   }
 
+  public Builder newBuilderForType() {
+    return newBuilder();
+  }
+
+  public Builder toBuilder() {
+    return newBuilder().mergeFrom(this);
+  }
+
   /**
    * Builder for {@link UnknownFieldSet}s.
    *
@@ -250,21 +277,35 @@ public final class UnknownFieldSet {
    *
    * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
    */
-  public static final class Builder {
+  public static final class Builder implements MessageLite.Builder {
+    private static ThreadLocalQuickQueue<Builder> builders =
+      new ThreadLocalQuickQueue<Builder>();
+
+    // This constructor should never be called directly (except from 'create').
     private Builder() {}
-    private Map<Integer, Field> fields = new TreeMap<Integer, Field>();
+
+    private Map<Integer, Field> fields;
 
     // Optimization:  We keep around a builder for the last field that was
     //   modified so that we can efficiently add to it multiple times in a
     //   row (important when parsing an unknown repeated field).
-    int lastFieldNumber = 0;
-    Field.Builder lastField = null;
+    private int lastFieldNumber;
+    private Field.Builder lastField;
+
+    private static Builder create() {
+      Builder builder = builders.get().poll();
+      if (builder == null) {
+        builder = new Builder();
+      }
+      builder.reinitialize();
+      return builder;
+    }
 
     /**
      * Get a field builder for the given field number which includes any
      * values that already exist.
      */
-    private Field.Builder getFieldBuilder(int number) {
+    private Field.Builder getFieldBuilder(final int number) {
       if (lastField != null) {
         if (number == lastFieldNumber) {
           return lastField;
@@ -275,7 +316,7 @@ public final class UnknownFieldSet {
       if (number == 0) {
         return null;
       } else {
-        Field existing = fields.get(number);
+        final Field existing = fields.get(number);
         lastFieldNumber = number;
         lastField = Field.newBuilder();
         if (existing != null) {
@@ -289,26 +330,48 @@ public final class UnknownFieldSet {
      * 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}.
+     * longer be usable.  Calling any method after {@code build()} will result
+     * in undefined behavior and can cause a {@code NullPointerException} to be
+     * thrown.
      */
     public UnknownFieldSet build() {
       getFieldBuilder(0);  // Force lastField to be built.
-      UnknownFieldSet result;
+      final UnknownFieldSet result;
       if (fields.isEmpty()) {
         result = getDefaultInstance();
       } else {
         result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
       }
       fields = null;
+      builders.get().offer(this);
       return result;
     }
 
-    /** Reset the builder to an empty set. */
-    public Builder clear() {
-      fields = new TreeMap<Integer, Field>();
+    public UnknownFieldSet buildPartial() {
+      // No required fields, so this is the same as build().
+      return build();
+    }
+
+    @Override
+    public Builder clone() {
+      getFieldBuilder(0);  // Force lastField to be built.
+      return UnknownFieldSet.newBuilder().mergeFrom(
+          new UnknownFieldSet(fields));
+    }
+
+    public UnknownFieldSet getDefaultInstanceForType() {
+      return UnknownFieldSet.getDefaultInstance();
+    }
+
+    private void reinitialize() {
+      fields = Collections.emptyMap();
       lastFieldNumber = 0;
       lastField = null;
+    }
+
+    /** Reset the builder to an empty set. */
+    public Builder clear() {
+      reinitialize();
       return this;
     }
 
@@ -317,9 +380,9 @@ public final class UnknownFieldSet {
      * 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) {
+    public Builder mergeFrom(final UnknownFieldSet other) {
       if (other != getDefaultInstance()) {
-        for (Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
+        for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
           mergeField(entry.getKey(), entry.getValue());
         }
       }
@@ -330,7 +393,7 @@ public final class UnknownFieldSet {
      * 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) {
+    public Builder mergeField(final int number, final Field field) {
       if (number == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
       }
@@ -350,7 +413,7 @@ public final class UnknownFieldSet {
      * value.  This is used in particular when an unknown enum value is
      * encountered.
      */
-    public Builder mergeVarintField(int number, int value) {
+    public Builder mergeVarintField(final int number, final int value) {
       if (number == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
       }
@@ -359,7 +422,7 @@ public final class UnknownFieldSet {
     }
 
     /** Check if the given field number is present in the set. */
-    public boolean hasField(int number) {
+    public boolean hasField(final int number) {
       if (number == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
       }
@@ -370,7 +433,7 @@ public final class UnknownFieldSet {
      * 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) {
+    public Builder addField(final int number, final Field field) {
       if (number == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
       }
@@ -379,6 +442,9 @@ public final class UnknownFieldSet {
         lastField = null;
         lastFieldNumber = 0;
       }
+      if (fields.isEmpty()) {
+        fields = new TreeMap<Integer,Field>();
+      }
       fields.put(number, field);
       return this;
     }
@@ -396,9 +462,9 @@ public final class UnknownFieldSet {
      * Parse an entire message from {@code input} and merge its fields into
      * this set.
      */
-    public Builder mergeFrom(CodedInputStream input) throws IOException {
+    public Builder mergeFrom(final CodedInputStream input) throws IOException {
       while (true) {
-        int tag = input.readTag();
+        final int tag = input.readTag();
         if (tag == 0 || !mergeFieldFrom(tag, input)) {
           break;
         }
@@ -411,9 +477,9 @@ public final class UnknownFieldSet {
      * @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)
+    public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
                                   throws IOException {
-      int number = WireFormat.getTagFieldNumber(tag);
+      final int number = WireFormat.getTagFieldNumber(tag);
       switch (WireFormat.getTagWireType(tag)) {
         case WireFormat.WIRETYPE_VARINT:
           getFieldBuilder(number).addVarint(input.readInt64());
@@ -424,12 +490,12 @@ public final class UnknownFieldSet {
         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);
+        case WireFormat.WIRETYPE_START_GROUP:
+          final Builder subBuilder = newBuilder();
+          input.readGroup(number, subBuilder,
+                          ExtensionRegistry.getEmptyRegistry());
           getFieldBuilder(number).addGroup(subBuilder.build());
           return true;
-        }
         case WireFormat.WIRETYPE_END_GROUP:
           return false;
         case WireFormat.WIRETYPE_FIXED32:
@@ -445,16 +511,16 @@ public final class UnknownFieldSet {
      * set being built.  This is just a small wrapper around
      * {@link #mergeFrom(CodedInputStream)}.
      */
-    public Builder mergeFrom(ByteString data)
+    public Builder mergeFrom(final ByteString data)
         throws InvalidProtocolBufferException {
       try {
-        CodedInputStream input = data.newCodedInput();
+        final CodedInputStream input = data.newCodedInput();
         mergeFrom(input);
         input.checkLastTagWas(0);
         return this;
-      } catch (InvalidProtocolBufferException e) {
+      } catch (final InvalidProtocolBufferException e) {
         throw e;
-      } catch (IOException e) {
+      } catch (final IOException e) {
         throw new RuntimeException(
           "Reading from a ByteString threw an IOException (should " +
           "never happen).", e);
@@ -466,16 +532,16 @@ public final class UnknownFieldSet {
      * set being built.  This is just a small wrapper around
      * {@link #mergeFrom(CodedInputStream)}.
      */
-    public Builder mergeFrom(byte[] data)
+    public Builder mergeFrom(final byte[] data)
         throws InvalidProtocolBufferException {
       try {
-        CodedInputStream input = CodedInputStream.newInstance(data);
+        final CodedInputStream input = CodedInputStream.newInstance(data);
         mergeFrom(input);
         input.checkLastTagWas(0);
         return this;
-      } catch (InvalidProtocolBufferException e) {
+      } catch (final InvalidProtocolBufferException e) {
         throw e;
-      } catch (IOException e) {
+      } catch (final IOException e) {
         throw new RuntimeException(
           "Reading from a byte array threw an IOException (should " +
           "never happen).", e);
@@ -487,12 +553,88 @@ public final class UnknownFieldSet {
      * 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);
+    public Builder mergeFrom(final InputStream input) throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
       mergeFrom(codedInput);
       codedInput.checkLastTagWas(0);
       return this;
     }
+
+    public Builder mergeDelimitedFrom(InputStream input)
+        throws IOException {
+      final int size = CodedInputStream.readRawVarint32(input);
+      final InputStream limitedInput =
+        new AbstractMessage.Builder.LimitedInputStream(input, size);
+      return mergeFrom(limitedInput, null);
+    }
+
+    public Builder mergeDelimitedFrom(
+        InputStream input,
+        ExtensionRegistryLite extensionRegistry) throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(input);
+    }
+
+    public Builder mergeFrom(
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry) throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(input);
+    }
+
+    public Builder mergeFrom(
+        ByteString data,
+        ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data);
+    }
+
+    public Builder mergeFrom(byte[] data, int off, int len)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    public Builder mergeFrom(
+        byte[] data,
+        ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data);
+    }
+
+    public Builder mergeFrom(
+        byte[] data, int off, int len,
+        ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data, off, len);
+    }
+
+    public Builder mergeFrom(
+        InputStream input,
+        ExtensionRegistryLite extensionRegistry) throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(input);
+    }
+
+    public boolean isInitialized() {
+      // UnknownFieldSets do not have required fields, so they are always
+      // initialized.
+      return true;
+    }
   }
 
   /**
@@ -510,7 +652,7 @@ public final class UnknownFieldSet {
    * wire types.
    *
    * <p>{@code Field} is an immutable class.  To construct one, you must use a
-   * {@link Field.Builder}.
+   * {@link Builder}.
    *
    * @see UnknownFieldSet
    */
@@ -519,22 +661,22 @@ public final class UnknownFieldSet {
 
     /** Construct a new {@link Builder}. */
     public static Builder newBuilder() {
-      return new Builder();
+      return Builder.create();
     }
 
     /**
      * 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);
+    public static Builder newBuilder(final Field copyFrom) {
+      return newBuilder().mergeFrom(copyFrom);
     }
 
     /** Get an empty {@code Field}. */
     public static Field getDefaultInstance() {
-      return defaultInstance;
+      return fieldDefaultInstance;
     }
-    private static Field defaultInstance = newBuilder().build();
+    private static final Field fieldDefaultInstance = newBuilder().build();
 
     /** Get the list of varint values for this field. */
     public List<Long> getVarintList()               { return varint;          }
@@ -556,14 +698,14 @@ public final class UnknownFieldSet {
     public List<UnknownFieldSet> getGroupList()      { return group;           }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(final Object other) {
       if (this == other) {
         return true;
       }
       if (!(other instanceof Field)) {
         return false;
       }
-      return Arrays.equals(this.getIdentityArray(),
+      return Arrays.equals(getIdentityArray(),
           ((Field) other).getIdentityArray());
     }
 
@@ -574,37 +716,37 @@ public final class UnknownFieldSet {
 
     /**
      * Returns the array of objects to be used to uniquely identify this
-     * {@link UnknownFieldSet.Field} instance.
+     * {@link Field} instance.
      */
     private Object[] getIdentityArray() {
       return new Object[] {
-          this.varint,
-          this.fixed32,
-          this.fixed64,
-          this.lengthDelimited,
-          this.group};
+          varint,
+          fixed32,
+          fixed64,
+          lengthDelimited,
+          group};
     }
 
     /**
      * Serializes the field, including field number, and writes it to
      * {@code output}.
      */
-    public void writeTo(int fieldNumber, CodedOutputStream output)
+    public void writeTo(final int fieldNumber, final CodedOutputStream output)
                         throws IOException {
-      for (long value : varint) {
+      for (final long value : varint) {
         output.writeUInt64(fieldNumber, value);
       }
-      for (int value : fixed32) {
+      for (final int value : fixed32) {
         output.writeFixed32(fieldNumber, value);
       }
-      for (long value : fixed64) {
+      for (final long value : fixed64) {
         output.writeFixed64(fieldNumber, value);
       }
-      for (ByteString value : lengthDelimited) {
+      for (final ByteString value : lengthDelimited) {
         output.writeBytes(fieldNumber, value);
       }
-      for (UnknownFieldSet value : group) {
-        output.writeUnknownGroup(fieldNumber, value);
+      for (final UnknownFieldSet value : group) {
+        output.writeGroup(fieldNumber, value);
       }
     }
 
@@ -612,22 +754,22 @@ public final class UnknownFieldSet {
      * Get the number of bytes required to encode this field, including field
      * number.
      */
-    public int getSerializedSize(int fieldNumber) {
+    public int getSerializedSize(final int fieldNumber) {
       int result = 0;
-      for (long value : varint) {
+      for (final long value : varint) {
         result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
       }
-      for (int value : fixed32) {
+      for (final int value : fixed32) {
         result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
       }
-      for (long value : fixed64) {
+      for (final long value : fixed64) {
         result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
       }
-      for (ByteString value : lengthDelimited) {
+      for (final ByteString value : lengthDelimited) {
         result += CodedOutputStream.computeBytesSize(fieldNumber, value);
       }
-      for (UnknownFieldSet value : group) {
-        result += CodedOutputStream.computeUnknownGroupSize(fieldNumber, value);
+      for (final UnknownFieldSet value : group) {
+        result += CodedOutputStream.computeGroupSize(fieldNumber, value);
       }
       return result;
     }
@@ -637,10 +779,10 @@ public final class UnknownFieldSet {
      * {@code output}, using {@code MessageSet} wire format.
      */
     public void writeAsMessageSetExtensionTo(
-        int fieldNumber,
-        CodedOutputStream output)
+        final int fieldNumber,
+        final CodedOutputStream output)
         throws IOException {
-      for (ByteString value : lengthDelimited) {
+      for (final ByteString value : lengthDelimited) {
         output.writeRawMessageSetExtension(fieldNumber, value);
       }
     }
@@ -649,9 +791,9 @@ public final class UnknownFieldSet {
      * Get the number of bytes required to encode this field, including field
      * number, using {@code MessageSet} wire format.
      */
-    public int getSerializedSizeAsMessageSetExtension(int fieldNumber) {
+    public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
       int result = 0;
-      for (ByteString value : lengthDelimited) {
+      for (final ByteString value : lengthDelimited) {
         result += CodedOutputStream.computeRawMessageSetExtensionSize(
           fieldNumber, value);
       }
@@ -670,13 +812,29 @@ public final class UnknownFieldSet {
      * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
      */
     public static final class Builder {
+      private static ThreadLocalQuickQueue<Builder> builders =
+        new ThreadLocalQuickQueue<Builder>();
+
+      // This constructor should never be called directly (except from 'create').
       private Builder() {}
-      private Field result = new Field();
+
+      private static Builder create() {
+        Builder builder = builders.get().poll();
+        if (builder == null) {
+          builder = new Builder();
+        }
+
+        builder.result = new Field();
+        return builder;
+      }
+
+      private Field result;
 
       /**
        * Build the field.  After {@code build()} has been called, the
        * {@code Builder} is no longer usable.  Calling any other method will
-       * throw a {@code NullPointerException}.
+       * result in undefined behavior and can cause a
+       * {@code NullPointerException} to be thrown.
        */
       public Field build() {
         if (result.varint == null) {
@@ -706,8 +864,9 @@ public final class UnknownFieldSet {
           result.group = Collections.unmodifiableList(result.group);
         }
 
-        Field returnMe = result;
+        final Field returnMe = result;
         result = null;
+        builders.get().offer(this);
         return returnMe;
       }
 
@@ -722,7 +881,7 @@ public final class UnknownFieldSet {
        * of values, {@code other}'s values are append to the ones in this
        * field.
        */
-      public Builder mergeFrom(Field other) {
+      public Builder mergeFrom(final Field other) {
         if (!other.varint.isEmpty()) {
           if (result.varint == null) {
             result.varint = new ArrayList<Long>();
@@ -757,7 +916,7 @@ public final class UnknownFieldSet {
       }
 
       /** Add a varint value. */
-      public Builder addVarint(long value) {
+      public Builder addVarint(final long value) {
         if (result.varint == null) {
           result.varint = new ArrayList<Long>();
         }
@@ -766,7 +925,7 @@ public final class UnknownFieldSet {
       }
 
       /** Add a fixed32 value. */
-      public Builder addFixed32(int value) {
+      public Builder addFixed32(final int value) {
         if (result.fixed32 == null) {
           result.fixed32 = new ArrayList<Integer>();
         }
@@ -775,7 +934,7 @@ public final class UnknownFieldSet {
       }
 
       /** Add a fixed64 value. */
-      public Builder addFixed64(long value) {
+      public Builder addFixed64(final long value) {
         if (result.fixed64 == null) {
           result.fixed64 = new ArrayList<Long>();
         }
@@ -784,7 +943,7 @@ public final class UnknownFieldSet {
       }
 
       /** Add a length-delimited value. */
-      public Builder addLengthDelimited(ByteString value) {
+      public Builder addLengthDelimited(final ByteString value) {
         if (result.lengthDelimited == null) {
           result.lengthDelimited = new ArrayList<ByteString>();
         }
@@ -793,7 +952,7 @@ public final class UnknownFieldSet {
       }
 
       /** Add an embedded group. */
-      public Builder addGroup(UnknownFieldSet value) {
+      public Builder addGroup(final UnknownFieldSet value) {
         if (result.group == null) {
           result.group = new ArrayList<UnknownFieldSet>();
         }

+ 62 - 32
java/src/main/java/com/google/protobuf/WireFormat.java

@@ -56,54 +56,84 @@ public final class WireFormat {
   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) {
+  static int getTagWireType(final int tag) {
     return tag & TAG_TYPE_MASK;
   }
 
   /** Given a tag value, determines the field number (the upper 29 bits). */
-  public static int getTagFieldNumber(int tag) {
+  public static int getTagFieldNumber(final int tag) {
     return tag >>> TAG_TYPE_BITS;
   }
 
   /** Makes a tag value given a field number and wire type. */
-  static int makeTag(int fieldNumber, int wireType) {
+  static int makeTag(final int fieldNumber, final 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;
+  /**
+   * Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}.  This is
+   * only here to support the lite runtime and should not be used by users.
+   */
+  public enum JavaType {
+    INT(0),
+    LONG(0L),
+    FLOAT(0F),
+    DOUBLE(0D),
+    BOOLEAN(false),
+    STRING(""),
+    BYTE_STRING(ByteString.EMPTY),
+    ENUM(null),
+    MESSAGE(null);
+
+    JavaType(final Object defaultDefault) {
+      this.defaultDefault = defaultDefault;
+    }
+
+    /**
+     * The default default value for fields of this type, if it's a primitive
+     * type.
+     */
+    Object getDefaultDefault() {
+      return defaultDefault;
     }
 
-    throw new RuntimeException(
-      "There is no way to get here, but the compiler thinks otherwise.");
+    private final Object defaultDefault;
   }
 
-  /** Given a field descriptor, returns the wire type. This differs from
-   * getWireFormatForFieldType for packed repeated fields. */
-  static int getWireFormatForField(Descriptors.FieldDescriptor descriptor) {
-    if (descriptor.getOptions().getPacked()) {
-      return WIRETYPE_LENGTH_DELIMITED;
-    } else {
-      return getWireFormatForFieldType(descriptor.getType());
+  /**
+   * Lite equivalent to {@link Descriptors.FieldDescriptor.Type}.  This is
+   * only here to support the lite runtime and should not be used by users.
+   */
+  public enum FieldType {
+    DOUBLE  (JavaType.DOUBLE     , WIRETYPE_FIXED64         ),
+    FLOAT   (JavaType.FLOAT      , WIRETYPE_FIXED32         ),
+    INT64   (JavaType.LONG       , WIRETYPE_VARINT          ),
+    UINT64  (JavaType.LONG       , WIRETYPE_VARINT          ),
+    INT32   (JavaType.INT        , WIRETYPE_VARINT          ),
+    FIXED64 (JavaType.LONG       , WIRETYPE_FIXED64         ),
+    FIXED32 (JavaType.INT        , WIRETYPE_FIXED32         ),
+    BOOL    (JavaType.BOOLEAN    , WIRETYPE_VARINT          ),
+    STRING  (JavaType.STRING     , WIRETYPE_LENGTH_DELIMITED),
+    GROUP   (JavaType.MESSAGE    , WIRETYPE_START_GROUP     ),
+    MESSAGE (JavaType.MESSAGE    , WIRETYPE_LENGTH_DELIMITED),
+    BYTES   (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED),
+    UINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
+    ENUM    (JavaType.ENUM       , WIRETYPE_VARINT          ),
+    SFIXED32(JavaType.INT        , WIRETYPE_FIXED32         ),
+    SFIXED64(JavaType.LONG       , WIRETYPE_FIXED64         ),
+    SINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
+    SINT64  (JavaType.LONG       , WIRETYPE_VARINT          );
+
+    FieldType(final JavaType javaType, final int wireType) {
+      this.javaType = javaType;
+      this.wireType = wireType;
     }
+
+    private final JavaType javaType;
+    private final int wireType;
+
+    public JavaType getJavaType() { return javaType; }
+    public int getWireType() { return wireType; }
   }
 
   // Field numbers for feilds in MessageSet wire format.

+ 30 - 0
java/src/test/java/com/google/protobuf/DescriptorsTest.java

@@ -367,4 +367,34 @@ public class DescriptorsTest extends TestCase {
     assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
       method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
   }
+
+  /**
+   * Test that the FieldDescriptor.Type enum is the same as the
+   * WireFormat.FieldType enum.
+   */
+  public void testFieldTypeTablesMatch() throws Exception {
+    FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
+    WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
+
+  /**
+   * Test that the FieldDescriptor.JavaType enum is the same as the
+   * WireFormat.JavaType enum.
+   */
+  public void testJavaTypeTablesMatch() throws Exception {
+    FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
+    WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
 }

+ 12 - 0
java/src/test/java/com/google/protobuf/DynamicMessageTest.java

@@ -73,6 +73,18 @@ public class DynamicMessageTest extends TestCase {
     }
   }
 
+  public void testClearAfterBuildError() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    builder.build();
+    try {
+      builder.clear();
+      fail("Should have thrown exception.");
+    } catch (IllegalStateException e) {
+      // Success.
+    }
+  }
+
   public void testDynamicMessageSettersRejectNull() throws Exception {
     Message.Builder builder =
       DynamicMessage.newBuilder(TestAllTypes.getDescriptor());

+ 89 - 0
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -43,6 +43,8 @@ import protobuf_unittest.MultipleFilesTestProto;
 import protobuf_unittest.MessageWithNoOuter;
 import protobuf_unittest.EnumWithNoOuter;
 import protobuf_unittest.ServiceWithNoOuter;
+import com.google.protobuf.UnittestLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 
 import junit.framework.TestCase;
 import java.util.Arrays;
@@ -82,6 +84,17 @@ public class GeneratedMessageTest extends TestCase {
     }
   }
 
+  public void testClearAfterBuildError() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.build();
+    try {
+      builder.clear();
+      fail("Should have thrown exception.");
+    } catch (IllegalStateException e) {
+      // Success.
+    }
+  }
+
   public void testSettersRejectNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
@@ -338,6 +351,16 @@ public class GeneratedMessageTest extends TestCase {
         instanceof ProtocolMessageEnum);
   }
 
+  public void testEnumMap() throws Exception {
+    Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
+
+    for (ForeignEnum value : ForeignEnum.values()) {
+      assertEquals(value, map.findValueByNumber(value.getNumber()));
+    }
+
+    assertTrue(map.findValueByNumber(12345) == null);
+  }
+
   // =================================================================
   // Extensions.
 
@@ -420,6 +443,12 @@ public class GeneratedMessageTest extends TestCase {
         .getExtensionCount(UnittestProto.repeatedInt32Extension));
   }
 
+  public void testExtensionCopy() throws Exception {
+    TestAllExtensions original = TestUtil.getAllExtensionsSet();
+    TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
+    TestUtil.assertAllExtensionsSet(copy);
+  }
+
   public void testExtensionMergeFrom() throws Exception {
     TestAllExtensions original =
       TestAllExtensions.newBuilder()
@@ -431,6 +460,66 @@ public class GeneratedMessageTest extends TestCase {
         1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
   }
 
+  // =================================================================
+  // Lite Extensions.
+
+  // We test lite extensions directly because they have a separate
+  // implementation from full extensions.  In contrast, we do not test
+  // lite fields directly since they are implemented exactly the same as
+  // regular fields.
+
+  public void testLiteExtensionAccessors() throws Exception {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestAllExtensionsLite message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testLiteExtensionRepeatedSetters() throws Exception {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestUtil.modifyRepeatedExtensions(builder);
+    TestAllExtensionsLite message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testLiteExtensionDefaults() throws Exception {
+    TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
+    TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
+  }
+
+  public void testClearLiteExtension() throws Exception {
+    // clearExtension() is not actually used in TestUtil, so try it manually.
+    assertFalse(
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
+        .clearExtension(UnittestLite.optionalInt32ExtensionLite)
+        .hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(0,
+      TestAllExtensionsLite.newBuilder()
+        .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
+        .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
+        .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
+  }
+
+  public void testLiteExtensionCopy() throws Exception {
+    TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
+    TestAllExtensionsLite copy =
+        TestAllExtensionsLite.newBuilder(original).build();
+    TestUtil.assertAllExtensionsSet(copy);
+  }
+
+  public void testLiteExtensionMergeFrom() throws Exception {
+    TestAllExtensionsLite original =
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
+    TestAllExtensionsLite merged =
+        TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
+    assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
+  }
+
   // =================================================================
   // multiple_files_test
 

+ 114 - 0
java/src/test/java/com/google/protobuf/LiteTest.java

@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
+
+import junit.framework.TestCase;
+
+/**
+ * Test lite runtime.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class LiteTest extends TestCase {
+  public void setUp() throws Exception {
+    // Test that nested extensions are initialized correctly even if the outer
+    // class has not been accessed directly.  This was once a bug with lite
+    // messages.
+    //
+    // We put this in setUp() rather than in its own test method because we
+    // need to make sure it runs before any actual tests.
+    assertTrue(TestNestedExtensionLite.nestedExtension != null);
+  }
+
+  public void testLite() throws Exception {
+    // Since lite messages are a subset of regular messages, we can mostly
+    // assume that the functionality of lite messages is already thoroughly
+    // tested by the regular tests.  All this test really verifies is that
+    // a proto with optimize_for = LITE_RUNTIME compiles correctly when
+    // linked only against the lite library.  That is all tested at compile
+    // time, leaving not much to do in this method.  Let's just do some random
+    // stuff to make sure the lite message is actually here and usable.
+
+    TestAllTypesLite message =
+      TestAllTypesLite.newBuilder()
+                      .setOptionalInt32(123)
+                      .addRepeatedString("hello")
+                      .setOptionalNestedMessage(
+                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+                      .build();
+
+    ByteString data = message.toByteString();
+
+    TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
+
+    assertEquals(123, message2.getOptionalInt32());
+    assertEquals(1, message2.getRepeatedStringCount());
+    assertEquals("hello", message2.getRepeatedString(0));
+    assertEquals(7, message2.getOptionalNestedMessage().getBb());
+  }
+
+  public void testLiteExtensions() throws Exception {
+    // TODO(kenton):  Unlike other features of the lite library, extensions are
+    //   implemented completely differently from the regular library.  We
+    //   need to test them more thoroughly, once they are fully-implemented.
+
+    TestAllExtensionsLite message =
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+            TestAllTypesLite.NestedEnum.BAZ)
+        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+        .build();
+
+    // Test copying a message, since coping extensions actually does use a
+    // different code path between lite and regular libraries, and as of this
+    // writing, parsing hasn't been implemented yet.
+    TestAllExtensionsLite message2 = message.toBuilder().build();
+
+    assertEquals(123, (int) message2.getExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(1, message2.getExtensionCount(
+        UnittestLite.repeatedStringExtensionLite));
+    assertEquals("hello", message2.getExtension(
+        UnittestLite.repeatedStringExtensionLite, 0));
+    assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
+        UnittestLite.optionalNestedEnumExtensionLite));
+    assertEquals(7, message2.getExtension(
+        UnittestLite.optionalNestedMessageExtensionLite).getBb());
+  }
+}

+ 945 - 86
java/src/test/java/com/google/protobuf/TestUtil.java

@@ -31,6 +31,7 @@
 package com.google.protobuf;
 
 import protobuf_unittest.UnittestProto;
+import com.google.protobuf.UnittestLite;
 
 // The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
 // import static protobuf_unittest.UnittestProto.*;
@@ -123,6 +124,95 @@ import static protobuf_unittest.UnittestProto.packedDoubleExtension;
 import static protobuf_unittest.UnittestProto.packedBoolExtension;
 import static protobuf_unittest.UnittestProto.packedEnumExtension;
 
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
+
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
@@ -132,6 +222,14 @@ import protobuf_unittest.UnittestProto.ForeignEnum;
 import com.google.protobuf.test.UnittestImport.ImportMessage;
 import com.google.protobuf.test.UnittestImport.ImportEnum;
 
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+
 import junit.framework.Assert;
 
 import java.io.File;
@@ -179,6 +277,12 @@ class TestUtil {
     return builder.build();
   }
 
+  public static TestAllExtensionsLite getAllLiteExtensionsSet() {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    setAllExtensions(builder);
+    return builder.build();
+  }
+
   public static TestPackedTypes getPackedSet() {
     TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
     setPackedFields(builder);
@@ -191,6 +295,13 @@ class TestUtil {
     return builder.build();
   }
 
+  public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
+    TestPackedExtensionsLite.Builder builder =
+        TestPackedExtensionsLite.newBuilder();
+    setPackedExtensions(builder);
+    return builder.build();
+  }
+
   /**
    * Set every field of {@code message} to the values expected by
    * {@code assertAllFieldsSet()}.
@@ -809,6 +920,90 @@ class TestUtil {
     Assert.assertEquals("525", message.getRepeatedCord(1));
   }
 
+  /**
+   * Set every field of {@code message} to a unique value.
+   */
+  public static void setPackedFields(TestPackedTypes.Builder message) {
+    message.addPackedInt32   (601);
+    message.addPackedInt64   (602);
+    message.addPackedUint32  (603);
+    message.addPackedUint64  (604);
+    message.addPackedSint32  (605);
+    message.addPackedSint64  (606);
+    message.addPackedFixed32 (607);
+    message.addPackedFixed64 (608);
+    message.addPackedSfixed32(609);
+    message.addPackedSfixed64(610);
+    message.addPackedFloat   (611);
+    message.addPackedDouble  (612);
+    message.addPackedBool    (true);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addPackedInt32   (701);
+    message.addPackedInt64   (702);
+    message.addPackedUint32  (703);
+    message.addPackedUint64  (704);
+    message.addPackedSint32  (705);
+    message.addPackedSint64  (706);
+    message.addPackedFixed32 (707);
+    message.addPackedFixed64 (708);
+    message.addPackedSfixed32(709);
+    message.addPackedSfixed64(710);
+    message.addPackedFloat   (711);
+    message.addPackedDouble  (712);
+    message.addPackedBool    (false);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAZ);
+  }
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setPackedFields}.
+   */
+  public static void assertPackedFieldsSet(TestPackedTypes message) {
+    Assert.assertEquals(2, message.getPackedInt32Count   ());
+    Assert.assertEquals(2, message.getPackedInt64Count   ());
+    Assert.assertEquals(2, message.getPackedUint32Count  ());
+    Assert.assertEquals(2, message.getPackedUint64Count  ());
+    Assert.assertEquals(2, message.getPackedSint32Count  ());
+    Assert.assertEquals(2, message.getPackedSint64Count  ());
+    Assert.assertEquals(2, message.getPackedFixed32Count ());
+    Assert.assertEquals(2, message.getPackedFixed64Count ());
+    Assert.assertEquals(2, message.getPackedSfixed32Count());
+    Assert.assertEquals(2, message.getPackedSfixed64Count());
+    Assert.assertEquals(2, message.getPackedFloatCount   ());
+    Assert.assertEquals(2, message.getPackedDoubleCount  ());
+    Assert.assertEquals(2, message.getPackedBoolCount    ());
+    Assert.assertEquals(2, message.getPackedEnumCount   ());
+    Assert.assertEquals(601  , message.getPackedInt32   (0));
+    Assert.assertEquals(602  , message.getPackedInt64   (0));
+    Assert.assertEquals(603  , message.getPackedUint32  (0));
+    Assert.assertEquals(604  , message.getPackedUint64  (0));
+    Assert.assertEquals(605  , message.getPackedSint32  (0));
+    Assert.assertEquals(606  , message.getPackedSint64  (0));
+    Assert.assertEquals(607  , message.getPackedFixed32 (0));
+    Assert.assertEquals(608  , message.getPackedFixed64 (0));
+    Assert.assertEquals(609  , message.getPackedSfixed32(0));
+    Assert.assertEquals(610  , message.getPackedSfixed64(0));
+    Assert.assertEquals(611  , message.getPackedFloat   (0), 0.0);
+    Assert.assertEquals(612  , message.getPackedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getPackedBool    (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
+    Assert.assertEquals(701  , message.getPackedInt32   (1));
+    Assert.assertEquals(702  , message.getPackedInt64   (1));
+    Assert.assertEquals(703  , message.getPackedUint32  (1));
+    Assert.assertEquals(704  , message.getPackedUint64  (1));
+    Assert.assertEquals(705  , message.getPackedSint32  (1));
+    Assert.assertEquals(706  , message.getPackedSint64  (1));
+    Assert.assertEquals(707  , message.getPackedFixed32 (1));
+    Assert.assertEquals(708  , message.getPackedFixed64 (1));
+    Assert.assertEquals(709  , message.getPackedSfixed32(1));
+    Assert.assertEquals(710  , message.getPackedSfixed64(1));
+    Assert.assertEquals(711  , message.getPackedFloat   (1), 0.0);
+    Assert.assertEquals(712  , message.getPackedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getPackedBool    (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
+  }
+
   // ===================================================================
   // Like above, but for extensions
 
@@ -846,6 +1041,18 @@ class TestUtil {
   private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
     Assert.assertEquals(a, b);
   }
+  private static void assertEqualsExactType(TestAllTypesLite.NestedEnum a,
+                                            TestAllTypesLite.NestedEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ForeignEnumLite a,
+                                            ForeignEnumLite b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ImportEnumLite a,
+                                            ImportEnumLite b) {
+    Assert.assertEquals(a, b);
+  }
 
   /**
    * Get an unmodifiable {@link ExtensionRegistry} containing all the
@@ -857,12 +1064,23 @@ class TestUtil {
     return registry.getUnmodifiable();
   }
 
+  public static ExtensionRegistryLite getExtensionRegistryLite() {
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    registerAllExtensionsLite(registry);
+    return registry.getUnmodifiable();
+  }
+
   /**
-   * Register all of {@code TestAllExtensions}' extensions with the
+   * Register all of {@code TestAllExtensions}'s extensions with the
    * given {@link ExtensionRegistry}.
    */
   public static void registerAllExtensions(ExtensionRegistry registry) {
     UnittestProto.registerAllExtensions(registry);
+    registerAllExtensionsLite(registry);
+  }
+
+  public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
+    UnittestLite.registerAllExtensions(registry);
   }
 
   /**
@@ -1509,90 +1727,6 @@ class TestUtil {
     assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1));
   }
 
-  /**
-   * Set every field of {@code message} to a unique value.
-   */
-  public static void setPackedFields(TestPackedTypes.Builder message) {
-    message.addPackedInt32   (601);
-    message.addPackedInt64   (602);
-    message.addPackedUint32  (603);
-    message.addPackedUint64  (604);
-    message.addPackedSint32  (605);
-    message.addPackedSint64  (606);
-    message.addPackedFixed32 (607);
-    message.addPackedFixed64 (608);
-    message.addPackedSfixed32(609);
-    message.addPackedSfixed64(610);
-    message.addPackedFloat   (611);
-    message.addPackedDouble  (612);
-    message.addPackedBool    (true);
-    message.addPackedEnum    (ForeignEnum.FOREIGN_BAR);
-    // Add a second one of each field.
-    message.addPackedInt32   (701);
-    message.addPackedInt64   (702);
-    message.addPackedUint32  (703);
-    message.addPackedUint64  (704);
-    message.addPackedSint32  (705);
-    message.addPackedSint64  (706);
-    message.addPackedFixed32 (707);
-    message.addPackedFixed64 (708);
-    message.addPackedSfixed32(709);
-    message.addPackedSfixed64(710);
-    message.addPackedFloat   (711);
-    message.addPackedDouble  (712);
-    message.addPackedBool    (false);
-    message.addPackedEnum    (ForeignEnum.FOREIGN_BAZ);
-  }
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are set to the values assigned by {@code setPackedFields}.
-   */
-  public static void assertPackedFieldsSet(TestPackedTypes message) {
-    Assert.assertEquals(2, message.getPackedInt32Count   ());
-    Assert.assertEquals(2, message.getPackedInt64Count   ());
-    Assert.assertEquals(2, message.getPackedUint32Count  ());
-    Assert.assertEquals(2, message.getPackedUint64Count  ());
-    Assert.assertEquals(2, message.getPackedSint32Count  ());
-    Assert.assertEquals(2, message.getPackedSint64Count  ());
-    Assert.assertEquals(2, message.getPackedFixed32Count ());
-    Assert.assertEquals(2, message.getPackedFixed64Count ());
-    Assert.assertEquals(2, message.getPackedSfixed32Count());
-    Assert.assertEquals(2, message.getPackedSfixed64Count());
-    Assert.assertEquals(2, message.getPackedFloatCount   ());
-    Assert.assertEquals(2, message.getPackedDoubleCount  ());
-    Assert.assertEquals(2, message.getPackedBoolCount    ());
-    Assert.assertEquals(2, message.getPackedEnumCount   ());
-    Assert.assertEquals(601  , message.getPackedInt32   (0));
-    Assert.assertEquals(602  , message.getPackedInt64   (0));
-    Assert.assertEquals(603  , message.getPackedUint32  (0));
-    Assert.assertEquals(604  , message.getPackedUint64  (0));
-    Assert.assertEquals(605  , message.getPackedSint32  (0));
-    Assert.assertEquals(606  , message.getPackedSint64  (0));
-    Assert.assertEquals(607  , message.getPackedFixed32 (0));
-    Assert.assertEquals(608  , message.getPackedFixed64 (0));
-    Assert.assertEquals(609  , message.getPackedSfixed32(0));
-    Assert.assertEquals(610  , message.getPackedSfixed64(0));
-    Assert.assertEquals(611  , message.getPackedFloat   (0), 0.0);
-    Assert.assertEquals(612  , message.getPackedDouble  (0), 0.0);
-    Assert.assertEquals(true , message.getPackedBool    (0));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
-    Assert.assertEquals(701  , message.getPackedInt32   (1));
-    Assert.assertEquals(702  , message.getPackedInt64   (1));
-    Assert.assertEquals(703  , message.getPackedUint32  (1));
-    Assert.assertEquals(704  , message.getPackedUint64  (1));
-    Assert.assertEquals(705  , message.getPackedSint32  (1));
-    Assert.assertEquals(706  , message.getPackedSint64  (1));
-    Assert.assertEquals(707  , message.getPackedFixed32 (1));
-    Assert.assertEquals(708  , message.getPackedFixed64 (1));
-    Assert.assertEquals(709  , message.getPackedSfixed32(1));
-    Assert.assertEquals(710  , message.getPackedSfixed64(1));
-    Assert.assertEquals(711  , message.getPackedFloat   (1), 0.0);
-    Assert.assertEquals(712  , message.getPackedDouble  (1), 0.0);
-    Assert.assertEquals(false, message.getPackedBool    (1));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
-  }
-
   public static void setPackedExtensions(TestPackedExtensions.Builder message) {
     message.addExtension(packedInt32Extension   , 601);
     message.addExtension(packedInt64Extension   , 602L);
@@ -1672,8 +1806,733 @@ class TestUtil {
                           message.getExtension(packedEnumExtension, 1));
   }
 
-
   // ===================================================================
+  // Lite extensions
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllExtensionsSet()}.
+   */
+  public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
+    message.setExtension(optionalInt32ExtensionLite   , 101);
+    message.setExtension(optionalInt64ExtensionLite   , 102L);
+    message.setExtension(optionalUint32ExtensionLite  , 103);
+    message.setExtension(optionalUint64ExtensionLite  , 104L);
+    message.setExtension(optionalSint32ExtensionLite  , 105);
+    message.setExtension(optionalSint64ExtensionLite  , 106L);
+    message.setExtension(optionalFixed32ExtensionLite , 107);
+    message.setExtension(optionalFixed64ExtensionLite , 108L);
+    message.setExtension(optionalSfixed32ExtensionLite, 109);
+    message.setExtension(optionalSfixed64ExtensionLite, 110L);
+    message.setExtension(optionalFloatExtensionLite   , 111F);
+    message.setExtension(optionalDoubleExtensionLite  , 112D);
+    message.setExtension(optionalBoolExtensionLite    , true);
+    message.setExtension(optionalStringExtensionLite  , "115");
+    message.setExtension(optionalBytesExtensionLite   , toBytes("116"));
+
+    message.setExtension(optionalGroupExtensionLite,
+      OptionalGroup_extension_lite.newBuilder().setA(117).build());
+    message.setExtension(optionalNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    message.setExtension(optionalForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(119).build());
+    message.setExtension(optionalImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(120).build());
+
+    message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.setExtension(optionalStringPieceExtensionLite, "124");
+    message.setExtension(optionalCordExtensionLite, "125");
+
+    // -----------------------------------------------------------------
+
+    message.addExtension(repeatedInt32ExtensionLite   , 201);
+    message.addExtension(repeatedInt64ExtensionLite   , 202L);
+    message.addExtension(repeatedUint32ExtensionLite  , 203);
+    message.addExtension(repeatedUint64ExtensionLite  , 204L);
+    message.addExtension(repeatedSint32ExtensionLite  , 205);
+    message.addExtension(repeatedSint64ExtensionLite  , 206L);
+    message.addExtension(repeatedFixed32ExtensionLite , 207);
+    message.addExtension(repeatedFixed64ExtensionLite , 208L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 209);
+    message.addExtension(repeatedSfixed64ExtensionLite, 210L);
+    message.addExtension(repeatedFloatExtensionLite   , 211F);
+    message.addExtension(repeatedDoubleExtensionLite  , 212D);
+    message.addExtension(repeatedBoolExtensionLite    , true);
+    message.addExtension(repeatedStringExtensionLite  , "215");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("216"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(217).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(219).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(220).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "224");
+    message.addExtension(repeatedCordExtensionLite, "225");
+
+    // Add a second one of each field.
+    message.addExtension(repeatedInt32ExtensionLite   , 301);
+    message.addExtension(repeatedInt64ExtensionLite   , 302L);
+    message.addExtension(repeatedUint32ExtensionLite  , 303);
+    message.addExtension(repeatedUint64ExtensionLite  , 304L);
+    message.addExtension(repeatedSint32ExtensionLite  , 305);
+    message.addExtension(repeatedSint64ExtensionLite  , 306L);
+    message.addExtension(repeatedFixed32ExtensionLite , 307);
+    message.addExtension(repeatedFixed64ExtensionLite , 308L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 309);
+    message.addExtension(repeatedSfixed64ExtensionLite, 310L);
+    message.addExtension(repeatedFloatExtensionLite   , 311F);
+    message.addExtension(repeatedDoubleExtensionLite  , 312D);
+    message.addExtension(repeatedBoolExtensionLite    , false);
+    message.addExtension(repeatedStringExtensionLite  , "315");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("316"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(317).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(319).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(320).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "324");
+    message.addExtension(repeatedCordExtensionLite, "325");
+
+    // -----------------------------------------------------------------
+
+    message.setExtension(defaultInt32ExtensionLite   , 401);
+    message.setExtension(defaultInt64ExtensionLite   , 402L);
+    message.setExtension(defaultUint32ExtensionLite  , 403);
+    message.setExtension(defaultUint64ExtensionLite  , 404L);
+    message.setExtension(defaultSint32ExtensionLite  , 405);
+    message.setExtension(defaultSint64ExtensionLite  , 406L);
+    message.setExtension(defaultFixed32ExtensionLite , 407);
+    message.setExtension(defaultFixed64ExtensionLite , 408L);
+    message.setExtension(defaultSfixed32ExtensionLite, 409);
+    message.setExtension(defaultSfixed64ExtensionLite, 410L);
+    message.setExtension(defaultFloatExtensionLite   , 411F);
+    message.setExtension(defaultDoubleExtensionLite  , 412D);
+    message.setExtension(defaultBoolExtensionLite    , false);
+    message.setExtension(defaultStringExtensionLite  , "415");
+    message.setExtension(defaultBytesExtensionLite   , toBytes("416"));
+
+    message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(defaultStringPieceExtensionLite, "424");
+    message.setExtension(defaultCordExtensionLite, "425");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated extensions of {@code message} to contain the values
+   * expected by {@code assertRepeatedExtensionsModified()}.
+   */
+  public static void modifyRepeatedExtensions(
+      TestAllExtensionsLite.Builder message) {
+    message.setExtension(repeatedInt32ExtensionLite   , 1, 501);
+    message.setExtension(repeatedInt64ExtensionLite   , 1, 502L);
+    message.setExtension(repeatedUint32ExtensionLite  , 1, 503);
+    message.setExtension(repeatedUint64ExtensionLite  , 1, 504L);
+    message.setExtension(repeatedSint32ExtensionLite  , 1, 505);
+    message.setExtension(repeatedSint64ExtensionLite  , 1, 506L);
+    message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
+    message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
+    message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
+    message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
+    message.setExtension(repeatedFloatExtensionLite   , 1, 511F);
+    message.setExtension(repeatedDoubleExtensionLite  , 1, 512D);
+    message.setExtension(repeatedBoolExtensionLite    , 1, true);
+    message.setExtension(repeatedStringExtensionLite  , 1, "515");
+    message.setExtension(repeatedBytesExtensionLite   , 1, toBytes("516"));
+
+    message.setExtension(repeatedGroupExtensionLite, 1,
+      RepeatedGroup_extension_lite.newBuilder().setA(517).build());
+    message.setExtension(repeatedNestedMessageExtensionLite, 1,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
+    message.setExtension(repeatedForeignMessageExtensionLite, 1,
+      ForeignMessageLite.newBuilder().setC(519).build());
+    message.setExtension(repeatedImportMessageExtensionLite, 1,
+      ImportMessageLite.newBuilder().setD(520).build());
+
+    message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
+    message.setExtension(repeatedCordExtensionLite, 1, "525");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}.
+   */
+  public static void assertAllExtensionsSet(TestAllExtensionsLite message) {
+    Assert.assertTrue(message.hasExtension(optionalInt32ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalInt64ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalUint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalUint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalSint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalSint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalFixed32ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalFixed64ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalSfixed32ExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalSfixed64ExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalFloatExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalDoubleExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalBoolExtensionLite    ));
+    Assert.assertTrue(message.hasExtension(optionalStringExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalBytesExtensionLite   ));
+
+    Assert.assertTrue(message.hasExtension(optionalGroupExtensionLite         ));
+    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalImportMessageExtensionLite ));
+
+    Assert.assertTrue(message.getExtension(optionalGroupExtensionLite         ).hasA());
+    Assert.assertTrue(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+    Assert.assertTrue(message.getExtension(optionalForeignMessageExtensionLite).hasC());
+    Assert.assertTrue(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+
+    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalImportEnumExtensionLite ));
+
+    Assert.assertTrue(message.hasExtension(optionalStringPieceExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalCordExtensionLite));
+
+    assertEqualsExactType(101  , message.getExtension(optionalInt32ExtensionLite   ));
+    assertEqualsExactType(102L , message.getExtension(optionalInt64ExtensionLite   ));
+    assertEqualsExactType(103  , message.getExtension(optionalUint32ExtensionLite  ));
+    assertEqualsExactType(104L , message.getExtension(optionalUint64ExtensionLite  ));
+    assertEqualsExactType(105  , message.getExtension(optionalSint32ExtensionLite  ));
+    assertEqualsExactType(106L , message.getExtension(optionalSint64ExtensionLite  ));
+    assertEqualsExactType(107  , message.getExtension(optionalFixed32ExtensionLite ));
+    assertEqualsExactType(108L , message.getExtension(optionalFixed64ExtensionLite ));
+    assertEqualsExactType(109  , message.getExtension(optionalSfixed32ExtensionLite));
+    assertEqualsExactType(110L , message.getExtension(optionalSfixed64ExtensionLite));
+    assertEqualsExactType(111F , message.getExtension(optionalFloatExtensionLite   ));
+    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtensionLite  ));
+    assertEqualsExactType(true , message.getExtension(optionalBoolExtensionLite    ));
+    assertEqualsExactType("115", message.getExtension(optionalStringExtensionLite  ));
+    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtensionLite));
+
+    assertEqualsExactType(117, message.getExtension(optionalGroupExtensionLite         ).getA());
+    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtensionLite).getC());
+    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtensionLite ).getD());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+      message.getExtension(optionalNestedEnumExtensionLite));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+      message.getExtension(optionalForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+      message.getExtension(optionalImportEnumExtensionLite));
+
+    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtensionLite));
+    assertEqualsExactType("125", message.getExtension(optionalCordExtensionLite));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtensionLite, 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(repeatedForeignEnumExtensionLite, 0));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+    assertEqualsExactType(301  , message.getExtension(repeatedInt32ExtensionLite   , 1));
+    assertEqualsExactType(302L , message.getExtension(repeatedInt64ExtensionLite   , 1));
+    assertEqualsExactType(303  , message.getExtension(repeatedUint32ExtensionLite  , 1));
+    assertEqualsExactType(304L , message.getExtension(repeatedUint64ExtensionLite  , 1));
+    assertEqualsExactType(305  , message.getExtension(repeatedSint32ExtensionLite  , 1));
+    assertEqualsExactType(306L , message.getExtension(repeatedSint64ExtensionLite  , 1));
+    assertEqualsExactType(307  , message.getExtension(repeatedFixed32ExtensionLite , 1));
+    assertEqualsExactType(308L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtensionLite   , 1));
+    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtensionLite  , 1));
+    assertEqualsExactType(false, message.getExtension(repeatedBoolExtensionLite    , 1));
+    assertEqualsExactType("315", message.getExtension(repeatedStringExtensionLite  , 1));
+    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+    assertEqualsExactType(317, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
+    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+      message.getExtension(repeatedNestedEnumExtensionLite, 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+      message.getExtension(repeatedForeignEnumExtensionLite, 1));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+      message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtensionLite, 1));
+    assertEqualsExactType("325", message.getExtension(repeatedCordExtensionLite, 1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasExtension(defaultInt32ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultInt64ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultUint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultUint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultSint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultSint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultFixed32ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultFixed64ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultSfixed32ExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultSfixed64ExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultFloatExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultDoubleExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultBoolExtensionLite    ));
+    Assert.assertTrue(message.hasExtension(defaultStringExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultBytesExtensionLite   ));
+
+    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultImportEnumExtensionLite ));
+
+    Assert.assertTrue(message.hasExtension(defaultStringPieceExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultCordExtensionLite));
+
+    assertEqualsExactType(401  , message.getExtension(defaultInt32ExtensionLite   ));
+    assertEqualsExactType(402L , message.getExtension(defaultInt64ExtensionLite   ));
+    assertEqualsExactType(403  , message.getExtension(defaultUint32ExtensionLite  ));
+    assertEqualsExactType(404L , message.getExtension(defaultUint64ExtensionLite  ));
+    assertEqualsExactType(405  , message.getExtension(defaultSint32ExtensionLite  ));
+    assertEqualsExactType(406L , message.getExtension(defaultSint64ExtensionLite  ));
+    assertEqualsExactType(407  , message.getExtension(defaultFixed32ExtensionLite ));
+    assertEqualsExactType(408L , message.getExtension(defaultFixed64ExtensionLite ));
+    assertEqualsExactType(409  , message.getExtension(defaultSfixed32ExtensionLite));
+    assertEqualsExactType(410L , message.getExtension(defaultSfixed64ExtensionLite));
+    assertEqualsExactType(411F , message.getExtension(defaultFloatExtensionLite   ));
+    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtensionLite  ));
+    assertEqualsExactType(false, message.getExtension(defaultBoolExtensionLite    ));
+    assertEqualsExactType("415", message.getExtension(defaultStringExtensionLite  ));
+    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtensionLite));
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(defaultNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(defaultForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(defaultImportEnumExtensionLite));
+
+    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
+    assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (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(TestAllExtensionsLite message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasExtension(optionalInt32ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalInt64ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalUint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalUint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalSint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalSint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalFixed32ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalFixed64ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalSfixed32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalSfixed64ExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalFloatExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalDoubleExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalBoolExtensionLite    ));
+    Assert.assertFalse(message.hasExtension(optionalStringExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalBytesExtensionLite   ));
+
+    Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite         ));
+    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite ));
+
+    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalImportEnumExtensionLite ));
+
+    Assert.assertFalse(message.hasExtension(optionalStringPieceExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalCordExtensionLite));
+
+    // Optional fields without defaults are set to zero or something like it.
+    assertEqualsExactType(0    , message.getExtension(optionalInt32ExtensionLite   ));
+    assertEqualsExactType(0L   , message.getExtension(optionalInt64ExtensionLite   ));
+    assertEqualsExactType(0    , message.getExtension(optionalUint32ExtensionLite  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalUint64ExtensionLite  ));
+    assertEqualsExactType(0    , message.getExtension(optionalSint32ExtensionLite  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalSint64ExtensionLite  ));
+    assertEqualsExactType(0    , message.getExtension(optionalFixed32ExtensionLite ));
+    assertEqualsExactType(0L   , message.getExtension(optionalFixed64ExtensionLite ));
+    assertEqualsExactType(0    , message.getExtension(optionalSfixed32ExtensionLite));
+    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64ExtensionLite));
+    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtensionLite   ));
+    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtensionLite  ));
+    assertEqualsExactType(false, message.getExtension(optionalBoolExtensionLite    ));
+    assertEqualsExactType(""   , message.getExtension(optionalStringExtensionLite  ));
+    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtensionLite));
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getExtension(optionalGroupExtensionLite         ).hasA());
+    Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+    Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite).hasC());
+    Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+
+    assertEqualsExactType(0, message.getExtension(optionalGroupExtensionLite         ).getA());
+    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtensionLite).getC());
+    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtensionLite ).getD());
+
+    // Enums without defaults are set to the first value in the enum.
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(optionalNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(optionalForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(optionalImportEnumExtensionLite));
+
+    assertEqualsExactType("", message.getExtension(optionalStringPieceExtensionLite));
+    assertEqualsExactType("", message.getExtension(optionalCordExtensionLite));
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtensionLite));
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasExtension(defaultInt32ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultInt64ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultUint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultUint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultSint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultSint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultFixed32ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultFixed64ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultSfixed32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultSfixed64ExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultFloatExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultDoubleExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultBoolExtensionLite    ));
+    Assert.assertFalse(message.hasExtension(defaultStringExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultBytesExtensionLite   ));
+
+    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultImportEnumExtensionLite ));
+
+    Assert.assertFalse(message.hasExtension(defaultStringPieceExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultCordExtensionLite));
+
+    // Fields with defaults have their default values (duh).
+    assertEqualsExactType( 41    , message.getExtension(defaultInt32ExtensionLite   ));
+    assertEqualsExactType( 42L   , message.getExtension(defaultInt64ExtensionLite   ));
+    assertEqualsExactType( 43    , message.getExtension(defaultUint32ExtensionLite  ));
+    assertEqualsExactType( 44L   , message.getExtension(defaultUint64ExtensionLite  ));
+    assertEqualsExactType(-45    , message.getExtension(defaultSint32ExtensionLite  ));
+    assertEqualsExactType( 46L   , message.getExtension(defaultSint64ExtensionLite  ));
+    assertEqualsExactType( 47    , message.getExtension(defaultFixed32ExtensionLite ));
+    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64ExtensionLite ));
+    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32ExtensionLite));
+    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64ExtensionLite));
+    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtensionLite   ));
+    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtensionLite  ));
+    assertEqualsExactType(true   , message.getExtension(defaultBoolExtensionLite    ));
+    assertEqualsExactType("hello", message.getExtension(defaultStringExtensionLite  ));
+    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtensionLite));
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(defaultNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(defaultForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(defaultImportEnumExtensionLite));
+
+    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
+    assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (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(
+      TestAllExtensionsLite message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtensionLite, 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(repeatedForeignEnumExtensionLite, 0));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+    // Actually verify the second (modified) elements now.
+    assertEqualsExactType(501  , message.getExtension(repeatedInt32ExtensionLite   , 1));
+    assertEqualsExactType(502L , message.getExtension(repeatedInt64ExtensionLite   , 1));
+    assertEqualsExactType(503  , message.getExtension(repeatedUint32ExtensionLite  , 1));
+    assertEqualsExactType(504L , message.getExtension(repeatedUint64ExtensionLite  , 1));
+    assertEqualsExactType(505  , message.getExtension(repeatedSint32ExtensionLite  , 1));
+    assertEqualsExactType(506L , message.getExtension(repeatedSint64ExtensionLite  , 1));
+    assertEqualsExactType(507  , message.getExtension(repeatedFixed32ExtensionLite , 1));
+    assertEqualsExactType(508L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtensionLite   , 1));
+    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtensionLite  , 1));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 1));
+    assertEqualsExactType("515", message.getExtension(repeatedStringExtensionLite  , 1));
+    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+    assertEqualsExactType(517, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
+    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(repeatedNestedEnumExtensionLite, 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(repeatedForeignEnumExtensionLite, 1));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtensionLite, 1));
+    assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
+  }
+
+  public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
+    message.addExtension(packedInt32ExtensionLite   , 601);
+    message.addExtension(packedInt64ExtensionLite   , 602L);
+    message.addExtension(packedUint32ExtensionLite  , 603);
+    message.addExtension(packedUint64ExtensionLite  , 604L);
+    message.addExtension(packedSint32ExtensionLite  , 605);
+    message.addExtension(packedSint64ExtensionLite  , 606L);
+    message.addExtension(packedFixed32ExtensionLite , 607);
+    message.addExtension(packedFixed64ExtensionLite , 608L);
+    message.addExtension(packedSfixed32ExtensionLite, 609);
+    message.addExtension(packedSfixed64ExtensionLite, 610L);
+    message.addExtension(packedFloatExtensionLite   , 611F);
+    message.addExtension(packedDoubleExtensionLite  , 612D);
+    message.addExtension(packedBoolExtensionLite    , true);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    // Add a second one of each field.
+    message.addExtension(packedInt32ExtensionLite   , 701);
+    message.addExtension(packedInt64ExtensionLite   , 702L);
+    message.addExtension(packedUint32ExtensionLite  , 703);
+    message.addExtension(packedUint64ExtensionLite  , 704L);
+    message.addExtension(packedSint32ExtensionLite  , 705);
+    message.addExtension(packedSint64ExtensionLite  , 706L);
+    message.addExtension(packedFixed32ExtensionLite , 707);
+    message.addExtension(packedFixed64ExtensionLite , 708L);
+    message.addExtension(packedSfixed32ExtensionLite, 709);
+    message.addExtension(packedSfixed64ExtensionLite, 710L);
+    message.addExtension(packedFloatExtensionLite   , 711F);
+    message.addExtension(packedDoubleExtensionLite  , 712D);
+    message.addExtension(packedBoolExtensionLite    , false);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+  }
+
+  public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
+    Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtensionLite));
+    assertEqualsExactType(601  , message.getExtension(packedInt32ExtensionLite   , 0));
+    assertEqualsExactType(602L , message.getExtension(packedInt64ExtensionLite   , 0));
+    assertEqualsExactType(603  , message.getExtension(packedUint32ExtensionLite  , 0));
+    assertEqualsExactType(604L , message.getExtension(packedUint64ExtensionLite  , 0));
+    assertEqualsExactType(605  , message.getExtension(packedSint32ExtensionLite  , 0));
+    assertEqualsExactType(606L , message.getExtension(packedSint64ExtensionLite  , 0));
+    assertEqualsExactType(607  , message.getExtension(packedFixed32ExtensionLite , 0));
+    assertEqualsExactType(608L , message.getExtension(packedFixed64ExtensionLite , 0));
+    assertEqualsExactType(609  , message.getExtension(packedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(610L , message.getExtension(packedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(611F , message.getExtension(packedFloatExtensionLite   , 0));
+    assertEqualsExactType(612D , message.getExtension(packedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(packedBoolExtensionLite    , 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+                          message.getExtension(packedEnumExtensionLite, 0));
+    assertEqualsExactType(701  , message.getExtension(packedInt32ExtensionLite   , 1));
+    assertEqualsExactType(702L , message.getExtension(packedInt64ExtensionLite   , 1));
+    assertEqualsExactType(703  , message.getExtension(packedUint32ExtensionLite  , 1));
+    assertEqualsExactType(704L , message.getExtension(packedUint64ExtensionLite  , 1));
+    assertEqualsExactType(705  , message.getExtension(packedSint32ExtensionLite  , 1));
+    assertEqualsExactType(706L , message.getExtension(packedSint64ExtensionLite  , 1));
+    assertEqualsExactType(707  , message.getExtension(packedFixed32ExtensionLite , 1));
+    assertEqualsExactType(708L , message.getExtension(packedFixed64ExtensionLite , 1));
+    assertEqualsExactType(709  , message.getExtension(packedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(710L , message.getExtension(packedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(711F , message.getExtension(packedFloatExtensionLite   , 1));
+    assertEqualsExactType(712D , message.getExtension(packedDoubleExtensionLite  , 1));
+    assertEqualsExactType(false, message.getExtension(packedBoolExtensionLite    , 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+                          message.getExtension(packedEnumExtensionLite, 1));
+  }
+
+  // =================================================================
 
   /**
    * Performs the same things that the methods of {@code TestUtil} do, but

+ 22 - 3
java/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -30,9 +30,12 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestProto.OneString;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestMset.TestMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@@ -173,6 +176,22 @@ public class TextFormatTest extends TestCase {
       TextFormat.printToString(message));
   }
 
+  public void testPrintField() throws Exception {
+    final FieldDescriptor dataField =
+      OneString.getDescriptor().findFieldByName("data");
+    assertEquals(
+      "data: \"test data\"\n",
+      TextFormat.printFieldToString(dataField, "test data"));
+
+    final FieldDescriptor optionalField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+    final Object value = NestedMessage.newBuilder().setBb(42).build();
+    
+    assertEquals(
+      "optional_nested_message {\n  bb: 42\n}\n",
+      TextFormat.printFieldToString(optionalField, value));
+  }
+  
   /**
    * Helper to construct a ByteString from a String containing only 8-bit
    * characters.  The characters are converted directly to bytes, *not*
@@ -450,21 +469,21 @@ public class TextFormatTest extends TestCase {
     try {
       TextFormat.unescapeText("\\x");
       fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequence e) {
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
 
     try {
       TextFormat.unescapeText("\\z");
       fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequence e) {
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
 
     try {
       TextFormat.unescapeText("\\");
       fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequence e) {
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
   }

+ 65 - 0
java/src/test/java/com/google/protobuf/WireFormatTest.java

@@ -45,6 +45,8 @@ import protobuf_unittest.UnittestMset.TestMessageSet;
 import protobuf_unittest.UnittestMset.RawMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 
 /**
  * Tests related to parsing and serialization.
@@ -100,6 +102,32 @@ public class WireFormatTest extends TestCase {
     assertEquals(rawBytes, rawBytes2);
   }
 
+  public void testSerializeExtensionsLite() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+    // it should work.
+
+    TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializePackedExtensionsLite() throws Exception {
+    // TestPackedTypes and TestPackedExtensions should have compatible wire
+    // formats; check that they serialize to the same string.
+    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    TestPackedTypes message2 = TestUtil.getPackedSet();
+    ByteString rawBytes2 = message2.toByteString();
+
+    assertEquals(rawBytes, rawBytes2);
+  }
+
   public void testParseExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -129,6 +157,43 @@ public class WireFormatTest extends TestCase {
     TestUtil.assertPackedExtensionsSet(message2);
   }
 
+  public void testParseExtensionsLite() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+    // it should work.
+
+    TestAllTypes message = TestUtil.getAllSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
+
+    TestAllExtensionsLite message2 =
+      TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
+
+    TestUtil.assertAllExtensionsSet(message2);
+
+    // Try again using a full extension registry.
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestAllExtensionsLite message3 =
+      TestAllExtensionsLite.parseFrom(rawBytes, registry);
+
+    TestUtil.assertAllExtensionsSet(message3);
+  }
+
+  public void testParsePackedExtensionsLite() throws Exception {
+    // Ensure that packed extensions can be properly parsed.
+    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
+
+    TestPackedExtensionsLite message2 =
+        TestPackedExtensionsLite.parseFrom(rawBytes, registry);
+
+    TestUtil.assertPackedExtensionsSet(message2);
+  }
+
   public void testExtensionsSerializedSize() throws Exception {
     assertEquals(TestUtil.getAllSet().getSerializedSize(),
                  TestUtil.getAllExtensionsSet().getSerializedSize());

+ 6 - 2
python/google/protobuf/internal/containers.py

@@ -112,9 +112,11 @@ class RepeatedScalarFieldContainer(BaseContainer):
       return
 
     orig_empty = len(self._values) == 0
+    new_values = []
     for elem in elem_seq:
       self._type_checker.CheckValue(elem)
-    self._values.extend(elem_seq)
+      new_values.append(elem)
+    self._values.extend(new_values)
     self._message_listener.ByteSizeDirty()
     if orig_empty:
       self._message_listener.TransitionToNonempty()
@@ -139,9 +141,11 @@ class RepeatedScalarFieldContainer(BaseContainer):
 
   def __setslice__(self, start, stop, values):
     """Sets the subset of items from between the specified indices."""
+    new_values = []
     for value in values:
       self._type_checker.CheckValue(value)
-    self._values[start:stop] = list(values)
+      new_values.append(value)
+    self._values[start:stop] = new_values
     self._message_listener.ByteSizeDirty()
 
   def __delitem__(self, key):

+ 2 - 2
python/google/protobuf/internal/decoder.py

@@ -135,12 +135,12 @@ class Decoder(object):
   def ReadFloat(self):
     """Reads and returns a 4-byte floating-point number."""
     serialized = self._stream.ReadBytes(4)
-    return struct.unpack('f', serialized)[0]
+    return struct.unpack(wire_format.FORMAT_FLOAT_LITTLE_ENDIAN, serialized)[0]
 
   def ReadDouble(self):
     """Reads and returns an 8-byte floating-point number."""
     serialized = self._stream.ReadBytes(8)
-    return struct.unpack('d', serialized)[0]
+    return struct.unpack(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, serialized)[0]
 
   def ReadBool(self):
     """Reads and returns a bool."""

+ 11 - 7
python/google/protobuf/internal/decoder_test.py

@@ -36,12 +36,12 @@ __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
+from google.protobuf.internal import encoder
 from google.protobuf.internal import input_stream
+from google.protobuf.internal import wire_format
 from google.protobuf import message
+import logging
 import mox
 
 
@@ -110,6 +110,10 @@ class DecoderTest(unittest.TestCase):
     self.mox.VerifyAll()
     self.mox.ResetAll()
 
+  VAL = 1.125  # Perfectly representable as a float (no rounding error).
+  LITTLE_FLOAT_VAL = '\x00\x00\x90?'
+  LITTLE_DOUBLE_VAL = '\x00\x00\x00\x00\x00\x00\xf2?'
+
   def testReadScalars(self):
     test_string = 'I can feel myself getting sutpider.'
     scalar_tests = [
@@ -125,10 +129,10 @@ class DecoderTest(unittest.TestCase):
          'ReadLittleEndian32', long(0xffffffff)],
         ['sfixed64', decoder.Decoder.ReadSFixed64, long(-1),
          'ReadLittleEndian64', 0xffffffffffffffff],
-        ['float', decoder.Decoder.ReadFloat, 0.0,
-         'ReadBytes', struct.pack('f', 0.0), 4],
-        ['double', decoder.Decoder.ReadDouble, 0.0,
-         'ReadBytes', struct.pack('d', 0.0), 8],
+        ['float', decoder.Decoder.ReadFloat, self.VAL,
+         'ReadBytes', self.LITTLE_FLOAT_VAL, 4],
+        ['double', decoder.Decoder.ReadDouble, self.VAL,
+         'ReadBytes', self.LITTLE_DOUBLE_VAL, 8],
         ['bool', decoder.Decoder.ReadBool, True, 'ReadVarUInt32', 1],
         ['enum', decoder.Decoder.ReadEnum, 23, 'ReadVarUInt32', 23],
         ['string', decoder.Decoder.ReadString,

+ 4 - 2
python/google/protobuf/internal/encoder.py

@@ -123,11 +123,13 @@ class Encoder(object):
 
   def AppendFloatNoTag(self, value):
     """Appends a floating-point number to our buffer."""
-    self._stream.AppendRawBytes(struct.pack('f', value))
+    self._stream.AppendRawBytes(
+        struct.pack(wire_format.FORMAT_FLOAT_LITTLE_ENDIAN, value))
 
   def AppendDoubleNoTag(self, value):
     """Appends a double-precision floating-point number to our buffer."""
-    self._stream.AppendRawBytes(struct.pack('d', value))
+    self._stream.AppendRawBytes(
+        struct.pack(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, value))
 
   def AppendBoolNoTag(self, value):
     """Appends a boolean to our buffer."""

+ 8 - 4
python/google/protobuf/internal/encoder_test.py

@@ -123,6 +123,10 @@ class EncoderTest(unittest.TestCase):
     self.mox.VerifyAll()
     self.mox.ResetAll()
 
+  VAL = 1.125  # Perfectly representable as a float (no rounding error).
+  LITTLE_FLOAT_VAL = '\x00\x00\x90?'
+  LITTLE_DOUBLE_VAL = '\x00\x00\x00\x00\x00\x00\xf2?'
+
   def testAppendScalars(self):
     utf8_bytes = '\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82'
     utf8_string = unicode(utf8_bytes, 'utf-8')
@@ -144,9 +148,9 @@ class EncoderTest(unittest.TestCase):
         ['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)],
+         wire_format.WIRETYPE_FIXED32, self.VAL, self.LITTLE_FLOAT_VAL],
         ['double', self.encoder.AppendDouble, 'AppendRawBytes',
-         wire_format.WIRETYPE_FIXED64, 0.0, struct.pack('d', 0.0)],
+         wire_format.WIRETYPE_FIXED64, self.VAL, self.LITTLE_DOUBLE_VAL],
         ['bool', self.encoder.AppendBool, 'AppendVarint32',
          wire_format.WIRETYPE_VARINT, False],
         ['enum', self.encoder.AppendEnum, 'AppendVarint32',
@@ -185,9 +189,9 @@ class EncoderTest(unittest.TestCase):
         ['sfixed64', self.encoder.AppendSFixed64NoTag,
          'AppendLittleEndian64', None, 0],
         ['float', self.encoder.AppendFloatNoTag,
-         'AppendRawBytes', None, 0.0, struct.pack('f', 0.0)],
+         'AppendRawBytes', None, self.VAL, self.LITTLE_FLOAT_VAL],
         ['double', self.encoder.AppendDoubleNoTag,
-         'AppendRawBytes', None, 0.0, struct.pack('d', 0.0)],
+         'AppendRawBytes', None, self.VAL, self.LITTLE_DOUBLE_VAL],
         ['bool', self.encoder.AppendBoolNoTag, 'AppendVarint32', None, 0],
         ['enum', self.encoder.AppendEnumNoTag, 'AppendVarint32', None, 0],
         ['sint32', self.encoder.AppendSInt32NoTag,

+ 53 - 0
python/google/protobuf/internal/message_test.py

@@ -0,0 +1,53 @@
+#! /usr/bin/python
+#
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# http://code.google.com/p/protobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests python protocol buffers against the golden message."""
+
+__author__ = 'gps@google.com (Gregory P. Smith)'
+
+import unittest
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf.internal import test_util
+
+
+class MessageTest(test_util.GoldenMessageTestCase):
+
+  def testGoldenMessage(self):
+    golden_data = test_util.GoldenFile('golden_message').read()
+    golden_message = unittest_pb2.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    self.ExpectAllFieldsSet(golden_message)
+
+
+if __name__ == '__main__':
+  unittest.main()

+ 84 - 4
python/google/protobuf/internal/reflection_test.py

@@ -232,13 +232,14 @@ class ReflectionTest(unittest.TestCase):
     proto.repeated_string.extend(['foo', 'bar'])
     proto.repeated_string.extend([])
     proto.repeated_string.append('baz')
+    proto.repeated_string.extend(str(x) for x in xrange(2))
     proto.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']) ],
+          ['foo', 'bar', 'baz', '0', '1']) ],
       proto.ListFields())
 
   def testSingularListExtensions(self):
@@ -447,6 +448,10 @@ class ReflectionTest(unittest.TestCase):
     self.assertEqual([25, 20, 15], proto.repeated_int32[1:4])
     self.assertEqual([5, 25, 20, 15, 30], proto.repeated_int32[:])
 
+    # Test slice assignment with an iterator
+    proto.repeated_int32[1:4] = (i for i in xrange(3))
+    self.assertEqual([5, 0, 1, 2, 30], proto.repeated_int32)
+
     # Test slice assignment.
     proto.repeated_int32[1:4] = [35, 40, 45]
     self.assertEqual([5, 35, 40, 45, 30], proto.repeated_int32)
@@ -1739,13 +1744,14 @@ class SerializationTest(unittest.TestCase):
     self.assertEqual(2, proto2.b)
     self.assertEqual(3, proto2.c)
 
-  def testSerializedAllPackedFields(self):
+  def testSerializeAllPackedFields(self):
     first_proto = unittest_pb2.TestPackedTypes()
     second_proto = unittest_pb2.TestPackedTypes()
     test_util.SetAllPackedFields(first_proto)
     serialized = first_proto.SerializeToString()
     self.assertEqual(first_proto.ByteSize(), len(serialized))
-    second_proto.MergeFromString(serialized)
+    bytes_read = second_proto.MergeFromString(serialized)
+    self.assertEqual(second_proto.ByteSize(), bytes_read)
     self.assertEqual(first_proto, second_proto)
 
   def testSerializeAllPackedExtensions(self):
@@ -1753,7 +1759,8 @@ class SerializationTest(unittest.TestCase):
     second_proto = unittest_pb2.TestPackedExtensions()
     test_util.SetAllPackedExtensions(first_proto)
     serialized = first_proto.SerializeToString()
-    second_proto.MergeFromString(serialized)
+    bytes_read = second_proto.MergeFromString(serialized)
+    self.assertEqual(second_proto.ByteSize(), bytes_read)
     self.assertEqual(first_proto, second_proto)
 
   def testMergePackedFromStringWhenSomeFieldsAlreadySet(self):
@@ -1838,6 +1845,79 @@ class SerializationTest(unittest.TestCase):
     self.assertEqual(unittest_pb2.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
       51)
 
+  def testInitKwargs(self):
+    proto = unittest_pb2.TestAllTypes(
+        optional_int32=1,
+        optional_string='foo',
+        optional_bool=True,
+        optional_bytes='bar',
+        optional_nested_message=unittest_pb2.TestAllTypes.NestedMessage(bb=1),
+        optional_foreign_message=unittest_pb2.ForeignMessage(c=1),
+        optional_nested_enum=unittest_pb2.TestAllTypes.FOO,
+        optional_foreign_enum=unittest_pb2.FOREIGN_FOO,
+        repeated_int32=[1, 2, 3])
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('optional_int32'))
+    self.assertTrue(proto.HasField('optional_string'))
+    self.assertTrue(proto.HasField('optional_bool'))
+    self.assertTrue(proto.HasField('optional_bytes'))
+    self.assertTrue(proto.HasField('optional_nested_message'))
+    self.assertTrue(proto.HasField('optional_foreign_message'))
+    self.assertTrue(proto.HasField('optional_nested_enum'))
+    self.assertTrue(proto.HasField('optional_foreign_enum'))
+    self.assertEqual(1, proto.optional_int32)
+    self.assertEqual('foo', proto.optional_string)
+    self.assertEqual(True, proto.optional_bool)
+    self.assertEqual('bar', proto.optional_bytes)
+    self.assertEqual(1, proto.optional_nested_message.bb)
+    self.assertEqual(1, proto.optional_foreign_message.c)
+    self.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                     proto.optional_nested_enum)
+    self.assertEqual(unittest_pb2.FOREIGN_FOO, proto.optional_foreign_enum)
+    self.assertEqual([1, 2, 3], proto.repeated_int32)
+
+  def testInitArgsUnknownFieldName(self):
+    def InitalizeEmptyMessageWithExtraKeywordArg():
+      unused_proto = unittest_pb2.TestEmptyMessage(unknown='unknown')
+    self._CheckRaises(ValueError,
+                      InitalizeEmptyMessageWithExtraKeywordArg,
+                      'Protocol message has no "unknown" field.')
+
+  def testInitRequiredKwargs(self):
+    proto = unittest_pb2.TestRequired(a=1, b=1, c=1)
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('a'))
+    self.assertTrue(proto.HasField('b'))
+    self.assertTrue(proto.HasField('c'))
+    self.assertTrue(not proto.HasField('dummy2'))
+    self.assertEqual(1, proto.a)
+    self.assertEqual(1, proto.b)
+    self.assertEqual(1, proto.c)
+
+  def testInitRequiredForeignKwargs(self):
+    proto = unittest_pb2.TestRequiredForeign(
+        optional_message=unittest_pb2.TestRequired(a=1, b=1, c=1))
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('optional_message'))
+    self.assertTrue(proto.optional_message.IsInitialized())
+    self.assertTrue(proto.optional_message.HasField('a'))
+    self.assertTrue(proto.optional_message.HasField('b'))
+    self.assertTrue(proto.optional_message.HasField('c'))
+    self.assertTrue(not proto.optional_message.HasField('dummy2'))
+    self.assertEqual(unittest_pb2.TestRequired(a=1, b=1, c=1),
+                     proto.optional_message)
+    self.assertEqual(1, proto.optional_message.a)
+    self.assertEqual(1, proto.optional_message.b)
+    self.assertEqual(1, proto.optional_message.c)
+
+  def testInitRepeatedKwargs(self):
+    proto = unittest_pb2.TestAllTypes(repeated_int32=[1, 2, 3])
+    self.assertTrue(proto.IsInitialized())
+    self.assertEqual(1, proto.repeated_int32[0])
+    self.assertEqual(2, proto.repeated_int32[1])
+    self.assertEqual(3, proto.repeated_int32[2])
+
+
 class OptionsTest(unittest.TestCase):
 
   def testMessageOptions(self):

+ 197 - 1
python/google/protobuf/internal/test_util.py

@@ -38,6 +38,7 @@ __author__ = 'robinson@google.com (Will Robinson)'
 
 import os.path
 
+import unittest
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_pb2
 
@@ -351,6 +352,200 @@ def ExpectAllFieldsAndExtensionsInOrder(serialized):
   if expected != serialized:
     raise ValueError('Expected %r, found %r' % (expected, serialized))
 
+
+class GoldenMessageTestCase(unittest.TestCase):
+  """This adds methods to TestCase useful for verifying our Golden Message."""
+
+  def ExpectAllFieldsSet(self, message):
+    """Check all fields for correct values have after Set*Fields() is called."""
+    self.assertTrue(message.HasField('optional_int32'))
+    self.assertTrue(message.HasField('optional_int64'))
+    self.assertTrue(message.HasField('optional_uint32'))
+    self.assertTrue(message.HasField('optional_uint64'))
+    self.assertTrue(message.HasField('optional_sint32'))
+    self.assertTrue(message.HasField('optional_sint64'))
+    self.assertTrue(message.HasField('optional_fixed32'))
+    self.assertTrue(message.HasField('optional_fixed64'))
+    self.assertTrue(message.HasField('optional_sfixed32'))
+    self.assertTrue(message.HasField('optional_sfixed64'))
+    self.assertTrue(message.HasField('optional_float'))
+    self.assertTrue(message.HasField('optional_double'))
+    self.assertTrue(message.HasField('optional_bool'))
+    self.assertTrue(message.HasField('optional_string'))
+    self.assertTrue(message.HasField('optional_bytes'))
+
+    self.assertTrue(message.HasField('optionalgroup'))
+    self.assertTrue(message.HasField('optional_nested_message'))
+    self.assertTrue(message.HasField('optional_foreign_message'))
+    self.assertTrue(message.HasField('optional_import_message'))
+
+    self.assertTrue(message.optionalgroup.HasField('a'))
+    self.assertTrue(message.optional_nested_message.HasField('bb'))
+    self.assertTrue(message.optional_foreign_message.HasField('c'))
+    self.assertTrue(message.optional_import_message.HasField('d'))
+
+    self.assertTrue(message.HasField('optional_nested_enum'))
+    self.assertTrue(message.HasField('optional_foreign_enum'))
+    self.assertTrue(message.HasField('optional_import_enum'))
+
+    self.assertTrue(message.HasField('optional_string_piece'))
+    self.assertTrue(message.HasField('optional_cord'))
+
+    self.assertEqual(101, message.optional_int32)
+    self.assertEqual(102, message.optional_int64)
+    self.assertEqual(103, message.optional_uint32)
+    self.assertEqual(104, message.optional_uint64)
+    self.assertEqual(105, message.optional_sint32)
+    self.assertEqual(106, message.optional_sint64)
+    self.assertEqual(107, message.optional_fixed32)
+    self.assertEqual(108, message.optional_fixed64)
+    self.assertEqual(109, message.optional_sfixed32)
+    self.assertEqual(110, message.optional_sfixed64)
+    self.assertEqual(111, message.optional_float)
+    self.assertEqual(112, message.optional_double)
+    self.assertEqual(True, message.optional_bool)
+    self.assertEqual('115', message.optional_string)
+    self.assertEqual('116', message.optional_bytes)
+
+    self.assertEqual(117, message.optionalgroup.a);
+    self.assertEqual(118, message.optional_nested_message.bb)
+    self.assertEqual(119, message.optional_foreign_message.c)
+    self.assertEqual(120, message.optional_import_message.d)
+
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
+    self.assertEqual(unittest_pb2.FOREIGN_BAZ, message.optional_foreign_enum)
+    self.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                     message.optional_import_enum)
+
+    # -----------------------------------------------------------------
+
+    self.assertEqual(2, len(message.repeated_int32))
+    self.assertEqual(2, len(message.repeated_int64))
+    self.assertEqual(2, len(message.repeated_uint32))
+    self.assertEqual(2, len(message.repeated_uint64))
+    self.assertEqual(2, len(message.repeated_sint32))
+    self.assertEqual(2, len(message.repeated_sint64))
+    self.assertEqual(2, len(message.repeated_fixed32))
+    self.assertEqual(2, len(message.repeated_fixed64))
+    self.assertEqual(2, len(message.repeated_sfixed32))
+    self.assertEqual(2, len(message.repeated_sfixed64))
+    self.assertEqual(2, len(message.repeated_float))
+    self.assertEqual(2, len(message.repeated_double))
+    self.assertEqual(2, len(message.repeated_bool))
+    self.assertEqual(2, len(message.repeated_string))
+    self.assertEqual(2, len(message.repeated_bytes))
+
+    self.assertEqual(2, len(message.repeatedgroup))
+    self.assertEqual(2, len(message.repeated_nested_message))
+    self.assertEqual(2, len(message.repeated_foreign_message))
+    self.assertEqual(2, len(message.repeated_import_message))
+    self.assertEqual(2, len(message.repeated_nested_enum))
+    self.assertEqual(2, len(message.repeated_foreign_enum))
+    self.assertEqual(2, len(message.repeated_import_enum))
+
+    self.assertEqual(2, len(message.repeated_string_piece))
+    self.assertEqual(2, len(message.repeated_cord))
+
+    self.assertEqual(201, message.repeated_int32[0])
+    self.assertEqual(202, message.repeated_int64[0])
+    self.assertEqual(203, message.repeated_uint32[0])
+    self.assertEqual(204, message.repeated_uint64[0])
+    self.assertEqual(205, message.repeated_sint32[0])
+    self.assertEqual(206, message.repeated_sint64[0])
+    self.assertEqual(207, message.repeated_fixed32[0])
+    self.assertEqual(208, message.repeated_fixed64[0])
+    self.assertEqual(209, message.repeated_sfixed32[0])
+    self.assertEqual(210, message.repeated_sfixed64[0])
+    self.assertEqual(211, message.repeated_float[0])
+    self.assertEqual(212, message.repeated_double[0])
+    self.assertEqual(True, message.repeated_bool[0])
+    self.assertEqual('215', message.repeated_string[0])
+    self.assertEqual('216', message.repeated_bytes[0])
+
+    self.assertEqual(217, message.repeatedgroup[0].a)
+    self.assertEqual(218, message.repeated_nested_message[0].bb)
+    self.assertEqual(219, message.repeated_foreign_message[0].c)
+    self.assertEqual(220, message.repeated_import_message[0].d)
+
+    self.assertEqual(unittest_pb2.TestAllTypes.BAR,
+                     message.repeated_nested_enum[0])
+    self.assertEqual(unittest_pb2.FOREIGN_BAR,
+                     message.repeated_foreign_enum[0])
+    self.assertEqual(unittest_import_pb2.IMPORT_BAR,
+                     message.repeated_import_enum[0])
+
+    self.assertEqual(301, message.repeated_int32[1])
+    self.assertEqual(302, message.repeated_int64[1])
+    self.assertEqual(303, message.repeated_uint32[1])
+    self.assertEqual(304, message.repeated_uint64[1])
+    self.assertEqual(305, message.repeated_sint32[1])
+    self.assertEqual(306, message.repeated_sint64[1])
+    self.assertEqual(307, message.repeated_fixed32[1])
+    self.assertEqual(308, message.repeated_fixed64[1])
+    self.assertEqual(309, message.repeated_sfixed32[1])
+    self.assertEqual(310, message.repeated_sfixed64[1])
+    self.assertEqual(311, message.repeated_float[1])
+    self.assertEqual(312, message.repeated_double[1])
+    self.assertEqual(False, message.repeated_bool[1])
+    self.assertEqual('315', message.repeated_string[1])
+    self.assertEqual('316', message.repeated_bytes[1])
+
+    self.assertEqual(317, message.repeatedgroup[1].a)
+    self.assertEqual(318, message.repeated_nested_message[1].bb)
+    self.assertEqual(319, message.repeated_foreign_message[1].c)
+    self.assertEqual(320, message.repeated_import_message[1].d)
+
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.repeated_nested_enum[1])
+    self.assertEqual(unittest_pb2.FOREIGN_BAZ,
+                     message.repeated_foreign_enum[1])
+    self.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                     message.repeated_import_enum[1])
+
+    # -----------------------------------------------------------------
+
+    self.assertTrue(message.HasField('default_int32'))
+    self.assertTrue(message.HasField('default_int64'))
+    self.assertTrue(message.HasField('default_uint32'))
+    self.assertTrue(message.HasField('default_uint64'))
+    self.assertTrue(message.HasField('default_sint32'))
+    self.assertTrue(message.HasField('default_sint64'))
+    self.assertTrue(message.HasField('default_fixed32'))
+    self.assertTrue(message.HasField('default_fixed64'))
+    self.assertTrue(message.HasField('default_sfixed32'))
+    self.assertTrue(message.HasField('default_sfixed64'))
+    self.assertTrue(message.HasField('default_float'))
+    self.assertTrue(message.HasField('default_double'))
+    self.assertTrue(message.HasField('default_bool'))
+    self.assertTrue(message.HasField('default_string'))
+    self.assertTrue(message.HasField('default_bytes'))
+
+    self.assertTrue(message.HasField('default_nested_enum'))
+    self.assertTrue(message.HasField('default_foreign_enum'))
+    self.assertTrue(message.HasField('default_import_enum'))
+
+    self.assertEqual(401, message.default_int32)
+    self.assertEqual(402, message.default_int64)
+    self.assertEqual(403, message.default_uint32)
+    self.assertEqual(404, message.default_uint64)
+    self.assertEqual(405, message.default_sint32)
+    self.assertEqual(406, message.default_sint64)
+    self.assertEqual(407, message.default_fixed32)
+    self.assertEqual(408, message.default_fixed64)
+    self.assertEqual(409, message.default_sfixed32)
+    self.assertEqual(410, message.default_sfixed64)
+    self.assertEqual(411, message.default_float)
+    self.assertEqual(412, message.default_double)
+    self.assertEqual(False, message.default_bool)
+    self.assertEqual('415', message.default_string)
+    self.assertEqual('416', message.default_bytes)
+
+    self.assertEqual(unittest_pb2.TestAllTypes.FOO, message.default_nested_enum)
+    self.assertEqual(unittest_pb2.FOREIGN_FOO, message.default_foreign_enum)
+    self.assertEqual(unittest_import_pb2.IMPORT_FOO,
+                     message.default_import_enum)
+
 def GoldenFile(filename):
   """Finds the given golden file and returns a file object representing it."""
 
@@ -359,7 +554,8 @@ def GoldenFile(filename):
   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))
+      full_path = os.path.join(path, 'src/google/protobuf/testdata', filename)
+      return open(full_path, 'rb')
     path = os.path.join(path, '..')
 
   raise RuntimeError(

+ 278 - 3
python/google/protobuf/internal/text_format_test.py

@@ -42,11 +42,16 @@ 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):
+
+class TextFormatTest(test_util.GoldenMessageTestCase):
+  def ReadGolden(self, golden_filename):
     f = test_util.GoldenFile(golden_filename)
     golden_lines = f.readlines()
     f.close()
+    return golden_lines
+
+  def CompareToGoldenFile(self, text, golden_filename):
+    golden_lines = self.ReadGolden(golden_filename)
     self.CompareToGoldenLines(text, golden_lines)
 
   def CompareToGoldenText(self, text, golden_text):
@@ -117,6 +122,276 @@ class TextFormatTest(unittest.TestCase):
     return text.replace('e+0','e+').replace('e+0','e+') \
                .replace('e-0','e-').replace('e-0','e-')
 
+  def testMergeGolden(self):
+    golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
+    parsed_message = unittest_pb2.TestAllTypes()
+    text_format.Merge(golden_text, parsed_message)
+
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.assertEquals(message, parsed_message)
+
+  def testMergeGoldenExtensions(self):
+    golden_text = '\n'.join(self.ReadGolden(
+        'text_format_unittest_extensions_data.txt'))
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Merge(golden_text, parsed_message)
+
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.assertEquals(message, parsed_message)
+
+  def testMergeAllFields(self):
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    ascii_text = text_format.MessageToString(message)
+
+    parsed_message = unittest_pb2.TestAllTypes()
+    text_format.Merge(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+    self.ExpectAllFieldsSet(message)
+
+  def testMergeAllExtensions(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    ascii_text = text_format.MessageToString(message)
+
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Merge(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testMergeMessageSet(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('repeated_uint64: 1\n'
+            'repeated_uint64: 2\n')
+    text_format.Merge(text, message)
+    self.assertEqual(1, message.repeated_uint64[0])
+    self.assertEqual(2, message.repeated_uint64[1])
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+            '    i: 23\n'
+            '  }\n'
+            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+            '    str: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEquals(23, message.message_set.Extensions[ext1].i)
+    self.assertEquals('foo', message.message_set.Extensions[ext2].str)
+
+  def testMergeExotic(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('repeated_int64: -9223372036854775808\n'
+            'repeated_uint64: 18446744073709551615\n'
+            'repeated_double: 123.456\n'
+            'repeated_double: 1.23e+22\n'
+            'repeated_double: 1.23e-18\n'
+            'repeated_string: \n'
+            '\"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\\"\"\n')
+    text_format.Merge(text, message)
+
+    self.assertEqual(-9223372036854775808, message.repeated_int64[0])
+    self.assertEqual(18446744073709551615, message.repeated_uint64[0])
+    self.assertEqual(123.456, message.repeated_double[0])
+    self.assertEqual(1.23e22, message.repeated_double[1])
+    self.assertEqual(1.23e-18, message.repeated_double[2])
+    self.assertEqual(
+        '\000\001\a\b\f\n\r\t\v\\\'\"', message.repeated_string[0])
+
+  def testMergeUnknownField(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'unknown_field: 8\n'
+    self.assertRaisesWithMessage(
+        text_format.ParseError,
+        ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
+         '"unknown_field".'),
+        text_format.Merge, text, message)
+
+  def testMergeBadExtension(self):
+    message = unittest_pb2.TestAllTypes()
+    text = '[unknown_extension]: 8\n'
+    self.assertRaisesWithMessage(
+        text_format.ParseError,
+        '1:2 : Extension "unknown_extension" not registered.',
+        text_format.Merge, text, message)
+
+  def testMergeGroupNotClosed(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'RepeatedGroup: <'
+    self.assertRaisesWithMessage(
+        text_format.ParseError, '1:16 : Expected ">".',
+        text_format.Merge, text, message)
+
+    text = 'RepeatedGroup: {'
+    self.assertRaisesWithMessage(
+        text_format.ParseError, '1:16 : Expected "}".',
+        text_format.Merge, text, message)
+
+  def testMergeBadEnumValue(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'optional_nested_enum: BARR'
+    self.assertRaisesWithMessage(
+        text_format.ParseError,
+        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
+         'has no value named BARR.'),
+        text_format.Merge, text, message)
+
+    message = unittest_pb2.TestAllTypes()
+    text = 'optional_nested_enum: 100'
+    self.assertRaisesWithMessage(
+        text_format.ParseError,
+        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
+         'has no value with number 100.'),
+        text_format.Merge, text, message)
+
+  def assertRaisesWithMessage(self, e_class, e, func, *args, **kwargs):
+    """Same as assertRaises, but also compares the exception message."""
+    if hasattr(e_class, '__name__'):
+      exc_name = e_class.__name__
+    else:
+      exc_name = str(e_class)
+
+    try:
+      func(*args, **kwargs)
+    except e_class, expr:
+      if str(expr) != e:
+        msg = '%s raised, but with wrong message: "%s" instead of "%s"'
+        raise self.failureException(msg % (exc_name,
+                                           str(expr).encode('string_escape'),
+                                           e.encode('string_escape')))
+      return
+    else:
+      raise self.failureException('%s not raised' % exc_name)
+
+
+class TokenizerTest(unittest.TestCase):
+
+  def testSimpleTokenCases(self):
+    text = ('identifier1:"string1"\n     \n\n'
+            'identifier2 : \n \n123  \n  identifier3 :\'string\'\n'
+            'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n'
+            'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n'
+            'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
+            'ID12: 2222222222222222222')
+    tokenizer = text_format._Tokenizer(text)
+    methods = [(tokenizer.ConsumeIdentifier, 'identifier1'),
+               ':',
+               (tokenizer.ConsumeString, 'string1'),
+               (tokenizer.ConsumeIdentifier, 'identifier2'),
+               ':',
+               (tokenizer.ConsumeInt32, 123),
+               (tokenizer.ConsumeIdentifier, 'identifier3'),
+               ':',
+               (tokenizer.ConsumeString, 'string'),
+               (tokenizer.ConsumeIdentifier, 'identifiER_4'),
+               ':',
+               (tokenizer.ConsumeFloat, 1.1e+2),
+               (tokenizer.ConsumeIdentifier, 'ID5'),
+               ':',
+               (tokenizer.ConsumeFloat, -0.23),
+               (tokenizer.ConsumeIdentifier, 'ID6'),
+               ':',
+               (tokenizer.ConsumeString, 'aaaa\'bbbb'),
+               (tokenizer.ConsumeIdentifier, 'ID7'),
+               ':',
+               (tokenizer.ConsumeString, 'aa\"bb'),
+               (tokenizer.ConsumeIdentifier, 'ID8'),
+               ':',
+               '{',
+               (tokenizer.ConsumeIdentifier, 'A'),
+               ':',
+               (tokenizer.ConsumeFloat, float('inf')),
+               (tokenizer.ConsumeIdentifier, 'B'),
+               ':',
+               (tokenizer.ConsumeFloat, float('-inf')),
+               (tokenizer.ConsumeIdentifier, 'C'),
+               ':',
+               (tokenizer.ConsumeBool, True),
+               (tokenizer.ConsumeIdentifier, 'D'),
+               ':',
+               (tokenizer.ConsumeBool, False),
+               '}',
+               (tokenizer.ConsumeIdentifier, 'ID9'),
+               ':',
+               (tokenizer.ConsumeUint32, 22),
+               (tokenizer.ConsumeIdentifier, 'ID10'),
+               ':',
+               (tokenizer.ConsumeInt64, -111111111111111111),
+               (tokenizer.ConsumeIdentifier, 'ID11'),
+               ':',
+               (tokenizer.ConsumeInt32, -22),
+               (tokenizer.ConsumeIdentifier, 'ID12'),
+               ':',
+               (tokenizer.ConsumeUint64, 2222222222222222222)]
+
+    i = 0
+    while not tokenizer.AtEnd():
+      m = methods[i]
+      if type(m) == str:
+        token = tokenizer.token
+        self.assertEqual(token, m)
+        tokenizer.NextToken()
+      else:
+        self.assertEqual(m[1], m[0]())
+      i += 1
+
+  def testConsumeIntegers(self):
+    # This test only tests the failures in the integer parsing methods as well
+    # as the '0' special cases.
+    int64_max = (1 << 63) - 1
+    uint32_max = (1 << 32) - 1
+    text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64)
+    self.assertEqual(-1, tokenizer.ConsumeInt32())
+
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32)
+    self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64())
+
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64)
+    self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64())
+    self.assertTrue(tokenizer.AtEnd())
+
+    text = '-0 -0 0 0'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertEqual(0, tokenizer.ConsumeUint32())
+    self.assertEqual(0, tokenizer.ConsumeUint64())
+    self.assertEqual(0, tokenizer.ConsumeUint32())
+    self.assertEqual(0, tokenizer.ConsumeUint64())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeByteString(self):
+    text = '"string1\''
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = 'string1"'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\xt"'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\"'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\x"'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+  def testConsumeBool(self):
+    text = 'not-a-bool'
+    tokenizer = text_format._Tokenizer(text)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
+
+
 if __name__ == '__main__':
   unittest.main()
-

+ 4 - 2
python/google/protobuf/internal/type_checkers.py

@@ -122,8 +122,10 @@ class UnicodeValueChecker(object):
       try:
         unicode(proposed_value, 'ascii')
       except UnicodeDecodeError:
-        raise ValueError('%.1024r isn\'t in 7-bit ASCII encoding.'
-                         % (proposed_value))
+        raise ValueError('%.1024r has type str, but isn\'t in 7-bit ASCII '
+                         'encoding. Non-ASCII strings must be converted to '
+                         'unicode objects before being added.' %
+                         (proposed_value))
 
 
 class Int32ValueChecker(IntValueChecker):

+ 2 - 0
python/google/protobuf/internal/wire_format.py

@@ -64,6 +64,8 @@ UINT64_MAX = (1 << 64) - 1
 # "struct" format strings that will encode/decode the specified formats.
 FORMAT_UINT32_LITTLE_ENDIAN = '<I'
 FORMAT_UINT64_LITTLE_ENDIAN = '<Q'
+FORMAT_FLOAT_LITTLE_ENDIAN = '<f'
+FORMAT_DOUBLE_LITTLE_ENDIAN = '<d'
 
 
 # We'll have to provide alternate implementations of AppendLittleEndian*() on

+ 1 - 2
python/google/protobuf/message.py

@@ -36,7 +36,6 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.protobuf import text_format
 
 class Error(Exception): pass
 class DecodeError(Error): pass
@@ -76,7 +75,7 @@ class Message(object):
     return not self == other_msg
 
   def __str__(self):
-    return text_format.MessageToString(self)
+    raise NotImplementedError
 
   def MergeFrom(self, other_msg):
     """Merges the contents of the specified message into current message.

+ 56 - 10
python/google/protobuf/reflection.py

@@ -62,6 +62,7 @@ from google.protobuf.internal import type_checkers
 from google.protobuf.internal import wire_format
 from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message as message_mod
+from google.protobuf import text_format
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
 
@@ -291,7 +292,7 @@ def _DefaultValueForField(message, field):
 def _AddInitMethod(message_descriptor, cls):
   """Adds an __init__ method to cls."""
   fields = message_descriptor.fields
-  def init(self):
+  def init(self, **kwargs):
     self._cached_byte_size = 0
     self._cached_byte_size_dirty = False
     self._listener = message_listener_mod.NullMessageListener()
@@ -306,12 +307,30 @@ def _AddInitMethod(message_descriptor, cls):
       if field.label != _FieldDescriptor.LABEL_REPEATED:
         setattr(self, _HasFieldName(field.name), False)
     self.Extensions = _ExtensionDict(self, cls._known_extensions)
+    for field_name, field_value in kwargs.iteritems():
+      field = _GetFieldByName(message_descriptor, field_name)
+      _MergeFieldOrExtension(self, field, field_value)
 
   init.__module__ = None
   init.__doc__ = None
   cls.__init__ = init
 
 
+def _GetFieldByName(message_descriptor, field_name):
+  """Returns a field descriptor by field name.
+
+  Args:
+    message_descriptor: A Descriptor describing all fields in message.
+    field_name: The name of the field to retrieve.
+  Returns:
+    The field descriptor associated with the field name.
+  """
+  try:
+    return message_descriptor.fields_by_name[field_name]
+  except KeyError:
+    raise ValueError('Protocol message has no "%s" field.' % field_name)
+
+
 def _AddPropertiesForFields(descriptor, cls):
   """Adds properties for all fields in this protocol message type."""
   for field in descriptor.fields:
@@ -543,10 +562,7 @@ def _AddHasFieldMethod(cls):
 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)
+    field = _GetFieldByName(self.DESCRIPTOR, field_name)
     proto_field_name = field.name
     python_field_name = _ValueFieldName(proto_field_name)
     has_field_name = _HasFieldName(proto_field_name)
@@ -629,6 +645,13 @@ def _AddEqualsMethod(message_descriptor, cls):
   cls.__eq__ = __eq__
 
 
+def _AddStrMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def __str__(self):
+    return text_format.MessageToString(self)
+  cls.__str__ = __str__
+
+
 def _AddSetListenerMethod(cls):
   """Helper for _AddMessageMethods()."""
   def SetListener(self, listener):
@@ -1090,7 +1113,7 @@ def _DeserializeOneEntity(message_descriptor, message, decoder):
       content_start = decoder.Position()
       while decoder.Position() - content_start < length:
         element_list.append(_DeserializeScalarFromDecoder(field_type, decoder))
-      return decoder.Position() - content_start
+      return decoder.Position() - initial_position
   else:
     # Repeated composite.
     composite = element_list.add()
@@ -1275,6 +1298,7 @@ def _AddMessageMethods(message_descriptor, cls):
   _AddClearMethod(cls)
   _AddHasExtensionMethod(cls)
   _AddEqualsMethod(message_descriptor, cls)
+  _AddStrMethod(message_descriptor, cls)
   _AddSetListenerMethod(cls)
   _AddByteSizeMethod(message_descriptor, cls)
   _AddSerializeToStringMethod(message_descriptor, cls)
@@ -1436,6 +1460,20 @@ class _ExtensionDict(object):
             if extension.label != _FieldDescriptor.LABEL_REPEATED)
     self._has_bits = dict.fromkeys(keys, False)
 
+    self._extensions_by_number = dict(
+        (f.number, f) for f in self._known_extensions.itervalues())
+
+    self._extensions_by_name = {}
+    for extension in self._known_extensions.itervalues():
+      if (extension.containing_type.GetOptions().message_set_wire_format and
+          extension.type == descriptor_mod.FieldDescriptor.TYPE_MESSAGE and
+          extension.message_type == extension.extension_scope and
+          extension.label == descriptor_mod.FieldDescriptor.LABEL_OPTIONAL):
+        extension_name = extension.message_type.full_name
+      else:
+        extension_name = extension.full_name
+      self._extensions_by_name[extension_name] = extension
+
   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
@@ -1609,7 +1647,15 @@ class _ExtensionDict(object):
     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())
+    return self._extensions_by_number
+
+  def _FindExtensionByName(self, name):
+    """Tries to find a known extension with the specified name.
+
+    Args:
+      name: Extension full name.
+
+    Returns:
+      Extension field descriptor.
+    """
+    return self._extensions_by_name.get(name, None)

+ 3 - 2
python/google/protobuf/service.py

@@ -67,8 +67,6 @@ class Service(object):
     and "done" will later be called with the response value.
 
     In the blocking case, RpcException will be raised on error.
-    Asynchronous calls must check status via the Failed method of the
-    RpcController.
 
     Preconditions:
     * method_descriptor.service == GetDescriptor
@@ -82,6 +80,9 @@ class Service(object):
     Postconditions:
     * "done" will be called when the method is complete.  This may be
       before CallMethod() returns or it may be at some point in the future.
+    * If the RPC failed, the response value passed to "done" will be None.
+      Further details about the failure can be found by querying the
+      RpcController.
     """
     raise NotImplementedError
 

+ 526 - 1
python/google/protobuf/text_format.py

@@ -33,10 +33,19 @@
 __author__ = 'kenton@google.com (Kenton Varda)'
 
 import cStringIO
+import re
 
+from collections import deque
+from google.protobuf.internal import type_checkers
 from google.protobuf import descriptor
 
-__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue' ]
+__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
+            'PrintFieldValue', 'Merge' ]
+
+
+class ParseError(Exception):
+  """Thrown in case of ASCII parsing error."""
+
 
 def MessageToString(message):
   out = cStringIO.StringIO()
@@ -45,6 +54,7 @@ def MessageToString(message):
   out.close()
   return result
 
+
 def PrintMessage(message, out, indent = 0):
   for field, value in message.ListFields():
     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
@@ -53,6 +63,7 @@ def PrintMessage(message, out, indent = 0):
     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."""
@@ -82,6 +93,7 @@ def PrintField(field, value, out, indent = 0):
   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."""
@@ -104,6 +116,507 @@ def PrintFieldValue(field, value, out, indent = 0):
   else:
     out.write(str(value))
 
+
+def Merge(text, message):
+  """Merges an ASCII representation of a protocol message into a message.
+
+  Args:
+    text: Message ASCII representation.
+    message: A protocol buffer message to merge into.
+
+  Raises:
+    ParseError: On ASCII parsing problems.
+  """
+  tokenizer = _Tokenizer(text)
+  while not tokenizer.AtEnd():
+    _MergeField(tokenizer, message)
+
+
+def _MergeField(tokenizer, message):
+  """Merges a single protocol message field into a message.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+    message: A protocol message to record the data.
+
+  Raises:
+    ParseError: In case of ASCII parsing problems.
+  """
+  message_descriptor = message.DESCRIPTOR
+  if tokenizer.TryConsume('['):
+    name = [tokenizer.ConsumeIdentifier()]
+    while tokenizer.TryConsume('.'):
+      name.append(tokenizer.ConsumeIdentifier())
+    name = '.'.join(name)
+
+    field = message.Extensions._FindExtensionByName(name)
+    if not field:
+      raise tokenizer.ParseErrorPreviousToken(
+          'Extension "%s" not registered.' % name)
+    elif message_descriptor != field.containing_type:
+      raise tokenizer.ParseErrorPreviousToken(
+          'Extension "%s" does not extend message type "%s".' % (
+              name, message_descriptor.full_name))
+    tokenizer.Consume(']')
+  else:
+    name = tokenizer.ConsumeIdentifier()
+    field = message_descriptor.fields_by_name.get(name, None)
+
+    # Group names are expected to be capitalized as they appear in the
+    # .proto file, which actually matches their type names, not their field
+    # names.
+    if not field:
+      field = message_descriptor.fields_by_name.get(name.lower(), None)
+      if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
+        field = None
+
+    if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
+        field.message_type.name != name):
+      field = None
+
+    if not field:
+      raise tokenizer.ParseErrorPreviousToken(
+          'Message type "%s" has no field named "%s".' % (
+              message_descriptor.full_name, name))
+
+  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+    tokenizer.TryConsume(':')
+
+    if tokenizer.TryConsume('<'):
+      end_token = '>'
+    else:
+      tokenizer.Consume('{')
+      end_token = '}'
+
+    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      if field.is_extension:
+        sub_message = message.Extensions[field].add()
+      else:
+        sub_message = getattr(message, field.name).add()
+    else:
+      if field.is_extension:
+        sub_message = message.Extensions[field]
+      else:
+        sub_message = getattr(message, field.name)
+
+    while not tokenizer.TryConsume(end_token):
+      if tokenizer.AtEnd():
+        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
+      _MergeField(tokenizer, sub_message)
+  else:
+    _MergeScalarField(tokenizer, message, field)
+
+
+def _MergeScalarField(tokenizer, message, field):
+  """Merges a single protocol message scalar field into a message.
+
+  Args:
+    tokenizer: A tokenizer to parse the field value.
+    message: A protocol message to record the data.
+    field: The descriptor of the field to be merged.
+
+  Raises:
+    ParseError: In case of ASCII parsing problems.
+    RuntimeError: On runtime errors.
+  """
+  tokenizer.Consume(':')
+  value = None
+
+  if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
+                    descriptor.FieldDescriptor.TYPE_SINT32,
+                    descriptor.FieldDescriptor.TYPE_SFIXED32):
+    value = tokenizer.ConsumeInt32()
+  elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
+                      descriptor.FieldDescriptor.TYPE_SINT64,
+                      descriptor.FieldDescriptor.TYPE_SFIXED64):
+    value = tokenizer.ConsumeInt64()
+  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
+                      descriptor.FieldDescriptor.TYPE_FIXED32):
+    value = tokenizer.ConsumeUint32()
+  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
+                      descriptor.FieldDescriptor.TYPE_FIXED64):
+    value = tokenizer.ConsumeUint64()
+  elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
+                      descriptor.FieldDescriptor.TYPE_DOUBLE):
+    value = tokenizer.ConsumeFloat()
+  elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
+    value = tokenizer.ConsumeBool()
+  elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
+    value = tokenizer.ConsumeString()
+  elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+    value = tokenizer.ConsumeByteString()
+  elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
+    # Enum can be specified by a number (the enum value), or by
+    # a string literal (the enum name).
+    enum_descriptor = field.enum_type
+    if tokenizer.LookingAtInteger():
+      number = tokenizer.ConsumeInt32()
+      enum_value = enum_descriptor.values_by_number.get(number, None)
+      if enum_value is None:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Enum type "%s" has no value with number %d.' % (
+                enum_descriptor.full_name, number))
+    else:
+      identifier = tokenizer.ConsumeIdentifier()
+      enum_value = enum_descriptor.values_by_name.get(identifier, None)
+      if enum_value is None:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Enum type "%s" has no value named %s.' % (
+                enum_descriptor.full_name, identifier))
+    value = enum_value.number
+  else:
+    raise RuntimeError('Unknown field type %d' % field.type)
+
+  if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+    if field.is_extension:
+      message.Extensions[field].append(value)
+    else:
+      getattr(message, field.name).append(value)
+  else:
+    if field.is_extension:
+      message.Extensions[field] = value
+    else:
+      setattr(message, field.name, value)
+
+
+class _Tokenizer(object):
+  """Protocol buffer ASCII representation tokenizer.
+
+  This class handles the lower level string parsing by splitting it into
+  meaningful tokens.
+
+  It was directly ported from the Java protocol buffer API.
+  """
+
+  _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
+  _TOKEN = re.compile(
+      '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier
+      '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number
+      '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string
+      '\'([^\"\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string
+  _IDENTIFIER = re.compile('\w+')
+  _INTEGER_CHECKERS = [type_checkers.Uint32ValueChecker(),
+                       type_checkers.Int32ValueChecker(),
+                       type_checkers.Uint64ValueChecker(),
+                       type_checkers.Int64ValueChecker()]
+  _FLOAT_INFINITY = re.compile('-?inf(inity)?f?', re.IGNORECASE)
+  _FLOAT_NAN = re.compile("nanf?", re.IGNORECASE)
+
+  def __init__(self, text_message):
+    self._text_message = text_message
+
+    self._position = 0
+    self._line = -1
+    self._column = 0
+    self._token_start = None
+    self.token = ''
+    self._lines = deque(text_message.split('\n'))
+    self._current_line = ''
+    self._previous_line = 0
+    self._previous_column = 0
+    self._SkipWhitespace()
+    self.NextToken()
+
+  def AtEnd(self):
+    """Checks the end of the text was reached.
+
+    Returns:
+      True iff the end was reached.
+    """
+    return not self._lines and not self._current_line
+
+  def _PopLine(self):
+    while not self._current_line:
+      if not self._lines:
+        self._current_line = ''
+        return
+      self._line += 1
+      self._column = 0
+      self._current_line = self._lines.popleft()
+
+  def _SkipWhitespace(self):
+    while True:
+      self._PopLine()
+      match = re.match(self._WHITESPACE, self._current_line)
+      if not match:
+        break
+      length = len(match.group(0))
+      self._current_line = self._current_line[length:]
+      self._column += length
+
+  def TryConsume(self, token):
+    """Tries to consume a given piece of text.
+
+    Args:
+      token: Text to consume.
+
+    Returns:
+      True iff the text was consumed.
+    """
+    if self.token == token:
+      self.NextToken()
+      return True
+    return False
+
+  def Consume(self, token):
+    """Consumes a piece of text.
+
+    Args:
+      token: Text to consume.
+
+    Raises:
+      ParseError: If the text couldn't be consumed.
+    """
+    if not self.TryConsume(token):
+      raise self._ParseError('Expected "%s".' % token)
+
+  def LookingAtInteger(self):
+    """Checks if the current token is an integer.
+
+    Returns:
+      True iff the current token is an integer.
+    """
+    if not self.token:
+      return False
+    c = self.token[0]
+    return (c >= '0' and c <= '9') or c == '-' or c == '+'
+
+  def ConsumeIdentifier(self):
+    """Consumes protocol message field identifier.
+
+    Returns:
+      Identifier string.
+
+    Raises:
+      ParseError: If an identifier couldn't be consumed.
+    """
+    result = self.token
+    if not re.match(self._IDENTIFIER, result):
+      raise self._ParseError('Expected identifier.')
+    self.NextToken()
+    return result
+
+  def ConsumeInt32(self):
+    """Consumes a signed 32bit integer number.
+
+    Returns:
+      The integer parsed.
+
+    Raises:
+      ParseError: If a signed 32bit integer couldn't be consumed.
+    """
+    try:
+      result = self._ParseInteger(self.token, is_signed=True, is_long=False)
+    except ValueError, e:
+      raise self._IntegerParseError(e)
+    self.NextToken()
+    return result
+
+  def ConsumeUint32(self):
+    """Consumes an unsigned 32bit integer number.
+
+    Returns:
+      The integer parsed.
+
+    Raises:
+      ParseError: If an unsigned 32bit integer couldn't be consumed.
+    """
+    try:
+      result = self._ParseInteger(self.token, is_signed=False, is_long=False)
+    except ValueError, e:
+      raise self._IntegerParseError(e)
+    self.NextToken()
+    return result
+
+  def ConsumeInt64(self):
+    """Consumes a signed 64bit integer number.
+
+    Returns:
+      The integer parsed.
+
+    Raises:
+      ParseError: If a signed 64bit integer couldn't be consumed.
+    """
+    try:
+      result = self._ParseInteger(self.token, is_signed=True, is_long=True)
+    except ValueError, e:
+      raise self._IntegerParseError(e)
+    self.NextToken()
+    return result
+
+  def ConsumeUint64(self):
+    """Consumes an unsigned 64bit integer number.
+
+    Returns:
+      The integer parsed.
+
+    Raises:
+      ParseError: If an unsigned 64bit integer couldn't be consumed.
+    """
+    try:
+      result = self._ParseInteger(self.token, is_signed=False, is_long=True)
+    except ValueError, e:
+      raise self._IntegerParseError(e)
+    self.NextToken()
+    return result
+
+  def ConsumeFloat(self):
+    """Consumes an floating point number.
+
+    Returns:
+      The number parsed.
+
+    Raises:
+      ParseError: If a floating point number couldn't be consumed.
+    """
+    text = self.token
+    if re.match(self._FLOAT_INFINITY, text):
+      self.NextToken()
+      if text.startswith('-'):
+        return float('-inf')
+      return float('inf')
+
+    if re.match(self._FLOAT_NAN, text):
+      self.NextToken()
+      return float('nan')
+
+    try:
+      result = float(text)
+    except ValueError, e:
+      raise self._FloatParseError(e)
+    self.NextToken()
+    return result
+
+  def ConsumeBool(self):
+    """Consumes a boolean value.
+
+    Returns:
+      The bool parsed.
+
+    Raises:
+      ParseError: If a boolean value couldn't be consumed.
+    """
+    if self.token == 'true':
+      self.NextToken()
+      return True
+    elif self.token == 'false':
+      self.NextToken()
+      return False
+    else:
+      raise self._ParseError('Expected "true" or "false".')
+
+  def ConsumeString(self):
+    """Consumes a string value.
+
+    Returns:
+      The string parsed.
+
+    Raises:
+      ParseError: If a string value couldn't be consumed.
+    """
+    return unicode(self.ConsumeByteString(), 'utf-8')
+
+  def ConsumeByteString(self):
+    """Consumes a byte array value.
+
+    Returns:
+      The array parsed (as a string).
+
+    Raises:
+      ParseError: If a byte array value couldn't be consumed.
+    """
+    text = self.token
+    if len(text) < 1 or text[0] not in ('\'', '"'):
+      raise self._ParseError('Exptected string.')
+
+    if len(text) < 2 or text[-1] != text[0]:
+      raise self._ParseError('String missing ending quote.')
+
+    try:
+      result = _CUnescape(text[1:-1])
+    except ValueError, e:
+      raise self._ParseError(str(e))
+    self.NextToken()
+    return result
+
+  def _ParseInteger(self, text, is_signed=False, is_long=False):
+    """Parses an integer.
+
+    Args:
+      text: The text to parse.
+      is_signed: True if a signed integer must be parsed.
+      is_long: True if a long integer must be parsed.
+
+    Returns:
+      The integer value.
+
+    Raises:
+      ValueError: Thrown Iff the text is not a valid integer.
+    """
+    pos = 0
+    if text.startswith('-'):
+      pos += 1
+
+    base = 10
+    if text.startswith('0x', pos) or text.startswith('0X', pos):
+      base = 16
+    elif text.startswith('0', pos):
+      base = 8
+
+    # Do the actual parsing. Exception handling is propagated to caller.
+    result = int(text, base)
+
+    # Check if the integer is sane. Exceptions handled by callers.
+    checker = self._INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
+    checker.CheckValue(result)
+    return result
+
+  def ParseErrorPreviousToken(self, message):
+    """Creates and *returns* a ParseError for the previously read token.
+
+    Args:
+      message: A message to set for the exception.
+
+    Returns:
+      A ParseError instance.
+    """
+    return ParseError('%d:%d : %s' % (
+        self._previous_line + 1, self._previous_column + 1, message))
+
+  def _ParseError(self, message):
+    """Creates and *returns* a ParseError for the current token."""
+    return ParseError('%d:%d : %s' % (
+        self._line + 1, self._column + 1, message))
+
+  def _IntegerParseError(self, e):
+    return self._ParseError('Couldn\'t parse integer: ' + str(e))
+
+  def _FloatParseError(self, e):
+    return self._ParseError('Couldn\'t parse number: ' + str(e))
+
+  def NextToken(self):
+    """Reads the next meaningful token."""
+    self._previous_line = self._line
+    self._previous_column = self._column
+    if self.AtEnd():
+      self.token = ''
+      return
+    self._column += len(self.token)
+
+    # Make sure there is data to work on.
+    self._PopLine()
+
+    match = re.match(self._TOKEN, self._current_line)
+    if match:
+      token = match.group(0)
+      self._current_line = self._current_line[len(token):]
+      self.token = token
+    else:
+      self.token = self._current_line[0]
+      self._current_line = self._current_line[1:]
+    self._SkipWhitespace()
+
+
 # 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,
@@ -123,3 +636,15 @@ def _CEscape(text):
     if o >= 127 or o < 32: return "\\%03o" % o # necessary escapes
     return c
   return "".join([escape(c) for c in text])
+
+
+_CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-f-A-F])')
+
+
+def _CUnescape(text):
+  def ReplaceHex(m):
+    return chr(int(m.group(0)[2:], 16))
+  # This is required because the 'string_escape' encoding doesn't
+  # allow single-digit hex escapes (like '\xf').
+  result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
+  return result.decode('string_escape')

+ 34 - 3
src/Makefile.am

@@ -43,21 +43,25 @@ nobase_include_HEADERS =                                       \
   google/protobuf/descriptor_database.h                        \
   google/protobuf/dynamic_message.h                            \
   google/protobuf/extension_set.h                              \
+  google/protobuf/generated_message_util.h                     \
   google/protobuf/generated_message_reflection.h               \
   google/protobuf/message.h                                    \
+  google/protobuf/message_lite.h                               \
   google/protobuf/reflection_ops.h                             \
   google/protobuf/repeated_field.h                             \
   google/protobuf/service.h                                    \
   google/protobuf/text_format.h                                \
   google/protobuf/unknown_field_set.h                          \
   google/protobuf/wire_format.h                                \
-  google/protobuf/wire_format_inl.h                            \
+  google/protobuf/wire_format_lite.h                           \
+  google/protobuf/wire_format_lite_inl.h                       \
   google/protobuf/io/coded_stream.h                            \
   $(GZHEADERS)                                                 \
   google/protobuf/io/printer.h                                 \
   google/protobuf/io/tokenizer.h                               \
   google/protobuf/io/zero_copy_stream.h                        \
   google/protobuf/io/zero_copy_stream_impl.h                   \
+  google/protobuf/io/zero_copy_stream_impl_lite.h              \
   google/protobuf/compiler/code_generator.h                    \
   google/protobuf/compiler/command_line_interface.h            \
   google/protobuf/compiler/importer.h                          \
@@ -68,6 +72,8 @@ nobase_include_HEADERS =                                       \
 
 lib_LTLIBRARIES = libprotobuf.la libprotoc.la
 
+# TODO(kenton):  Separate lite and full libraries.  Also make sure lite_unittest
+#   only links against the lite lib.
 libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
 libprotobuf_la_LDFLAGS = -version-info 3:0:0
 libprotobuf_la_SOURCES =                                       \
@@ -89,20 +95,25 @@ libprotobuf_la_SOURCES =                                       \
   google/protobuf/descriptor_database.cc                       \
   google/protobuf/dynamic_message.cc                           \
   google/protobuf/extension_set.cc                             \
+  google/protobuf/extension_set_heavy.cc                       \
+  google/protobuf/generated_message_util.cc                    \
   google/protobuf/generated_message_reflection.cc              \
   google/protobuf/message.cc                                   \
+  google/protobuf/message_lite.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/wire_format_lite.cc                          \
   google/protobuf/io/coded_stream.cc                           \
   google/protobuf/io/gzip_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/io/zero_copy_stream_impl_lite.cc             \
   google/protobuf/compiler/importer.cc                         \
   google/protobuf/compiler/parser.cc
 
@@ -171,6 +182,9 @@ protoc_inputs =                                                \
   google/protobuf/unittest_optimize_for.proto                  \
   google/protobuf/unittest_embed_optimize_for.proto            \
   google/protobuf/unittest_custom_options.proto                \
+  google/protobuf/unittest_lite.proto                          \
+  google/protobuf/unittest_import_lite.proto                   \
+  google/protobuf/unittest_lite_imports_nonlite.proto          \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
 
 EXTRA_DIST =                                                   \
@@ -186,7 +200,14 @@ EXTRA_DIST =                                                   \
   google/protobuf/io/package_info.h                            \
   google/protobuf/compiler/package_info.h
 
+protoc_lite_outputs =                                          \
+  google/protobuf/unittest_lite.pb.cc                          \
+  google/protobuf/unittest_lite.pb.h                           \
+  google/protobuf/unittest_import_lite.pb.cc                   \
+  google/protobuf/unittest_import_lite.pb.h
+
 protoc_outputs =                                               \
+  $(protoc_lite_outputs)                                       \
   google/protobuf/unittest.pb.cc                               \
   google/protobuf/unittest.pb.h                                \
   google/protobuf/unittest_empty.pb.cc                         \
@@ -201,6 +222,8 @@ protoc_outputs =                                               \
   google/protobuf/unittest_embed_optimize_for.pb.h             \
   google/protobuf/unittest_custom_options.pb.cc                \
   google/protobuf/unittest_custom_options.pb.h                 \
+  google/protobuf/unittest_lite_imports_nonlite.pb.cc          \
+  google/protobuf/unittest_lite_imports_nonlite.pb.h           \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc  \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
 
@@ -240,7 +263,7 @@ COMMON_TEST_SOURCES =                                          \
   google/protobuf/testing/file.cc                              \
   google/protobuf/testing/file.h
 
-check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test $(GZCHECKPROGRAMS)
+check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZCHECKPROGRAMS)
 protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
                       $(top_builddir)/gtest/lib/libgtest.la       \
                       $(top_builddir)/gtest/lib/libgtest_main.la
@@ -290,6 +313,14 @@ protobuf_lazy_descriptor_test_SOURCES =                        \
   $(COMMON_TEST_SOURCES)
 nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
 
+# Build lite_unittest separately, since it doesn't use gtest.
+protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la
+protobuf_lite_test_SOURCES =                                           \
+  google/protobuf/lite_unittest.cc                                     \
+  google/protobuf/test_util_lite.cc                                    \
+  google/protobuf/test_util_lite.h
+nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
+
 if HAVE_ZLIB
 zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
 zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc
@@ -298,4 +329,4 @@ zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
 zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
 endif
 
-TESTS = protobuf-test protobuf-lazy-descriptor-test $(GZTESTS)
+TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZTESTS)

+ 22 - 0
src/google/protobuf/compiler/code_generator.cc

@@ -34,6 +34,8 @@
 
 #include <google/protobuf/compiler/code_generator.h>
 
+#include <google/protobuf/stubs/strutil.h>
+
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -41,6 +43,26 @@ namespace compiler {
 CodeGenerator::~CodeGenerator() {}
 OutputDirectory::~OutputDirectory() {}
 
+// Parses a set of comma-delimited name/value pairs.
+void ParseGeneratorParameter(const string& text,
+			     vector<pair<string, string> >* output) {
+  vector<string> parts;
+  SplitStringUsing(text, ",", &parts);
+
+  for (int i = 0; i < parts.size(); i++) {
+    string::size_type equals_pos = parts[i].find_first_of('=');
+    pair<string, string> value;
+    if (equals_pos == string::npos) {
+      value.first = parts[i];
+      value.second = "";
+    } else {
+      value.first = parts[i].substr(0, equals_pos);
+      value.second = parts[i].substr(equals_pos + 1);
+    }
+    output->push_back(value);
+  }
+}
+
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace google

+ 11 - 0
src/google/protobuf/compiler/code_generator.h

@@ -40,6 +40,8 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <string>
+#include <vector>
+#include <utility>
 
 namespace google {
 namespace protobuf {
@@ -105,6 +107,15 @@ class LIBPROTOC_EXPORT OutputDirectory {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory);
 };
 
+// Several code generators treat the parameter argument as holding a
+// list of options separated by commas.  This helper function parses
+// a set of comma-delimited name/value pairs: e.g.,
+//   "foo=bar,baz,qux=corge"
+// parses to the pairs:
+//   ("foo", "bar"), ("baz", ""), ("qux", "corge")
+extern void ParseGeneratorParameter(const string&,
+				    vector<pair<string, string> >*);
+
 }  // namespace compiler
 }  // namespace protobuf
 

+ 51 - 28
src/google/protobuf/compiler/cpp/cpp_enum.cc

@@ -95,24 +95,39 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
   }
 
   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");
 
-  // The _Name and _Parse methods
-  printer->Print(vars,
-    "inline const ::std::string& $classname$_Name($classname$ value) {\n"
-    "  return ::google::protobuf::internal::NameOfEnum(\n"
-    "    $classname$_descriptor(), value);\n"
-    "}\n");
-  printer->Print(vars,
-    "inline bool $classname$_Parse(\n"
-    "    const ::std::string& name, $classname$* value) {\n"
-    "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
-    "    $classname$_descriptor(), name, value);\n"
-    "}\n");
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(vars,
+      "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
+    // The _Name and _Parse methods
+    printer->Print(vars,
+      "inline const ::std::string& $classname$_Name($classname$ value) {\n"
+      "  return ::google::protobuf::internal::NameOfEnum(\n"
+      "    $classname$_descriptor(), value);\n"
+      "}\n");
+    printer->Print(vars,
+      "inline bool $classname$_Parse(\n"
+      "    const ::std::string& name, $classname$* value) {\n"
+      "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
+      "    $classname$_descriptor(), name, value);\n"
+      "}\n");
+  }
+}
+
+void EnumGenerator::
+GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(
+      "template <>\n"
+      "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
+      "  return $classname$_descriptor();\n"
+      "}\n",
+      "classname", ClassName(descriptor_, true));
+  }
 }
 
 void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
@@ -128,24 +143,28 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
   }
 
   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 inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
-    "  return $classname$_Name(value);\n"
-    "}\n"
-    "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
-    "    $nested_name$* value) {\n"
-    "  return $classname$_Parse(name, 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");
+
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(vars,
+      "static inline const ::google::protobuf::EnumDescriptor*\n"
+      "$nested_name$_descriptor() {\n"
+      "  return $classname$_descriptor();\n"
+      "}\n"
+      "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
+      "  return $classname$_Name(value);\n"
+      "}\n"
+      "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
+      "    $nested_name$* value) {\n"
+      "  return $classname$_Parse(name, value);\n"
+      "}\n");
+  }
 }
 
 void EnumGenerator::GenerateDescriptorInitializer(
@@ -168,11 +187,15 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
   map<string, string> vars;
   vars["classname"] = classname_;
 
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(vars,
+      "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
+      "  protobuf_AssignDescriptorsOnce();\n"
+      "  return $classname$_descriptor_;\n"
+      "}\n");
+  }
+
   printer->Print(vars,
-    "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
-    "  protobuf_AssignDescriptorsOnce();\n"
-    "  return $classname$_descriptor_;\n"
-    "}\n"
     "bool $classname$_IsValid(int value) {\n"
     "  switch(value) {\n");
 

+ 4 - 0
src/google/protobuf/compiler/cpp/cpp_enum.h

@@ -63,6 +63,10 @@ class EnumGenerator {
   // nested enums.
   void GenerateDefinition(io::Printer* printer);
 
+  // Generate specialization of GetEnumDescriptor<MyEnum>().
+  // Precondition: in ::google::protobuf namespace.
+  void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
+
   // For enums nested within a message, generate code to import all the enum's
   // symbols (e.g. the enum type name, all its values, etc.) into the class's
   // namespace.  This should be placed inside the class definition in the

+ 52 - 55
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -35,7 +35,7 @@
 #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/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
 
 namespace google {
@@ -43,24 +43,14 @@ 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) {
+  SetCommonFieldVariables(descriptor, 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
@@ -83,8 +73,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void EnumFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$() const;\n"
-    "inline void set_$name$($type$ value);\n");
+    "inline $type$ $name$() const$deprecation$;\n"
+    "inline void set_$name$($type$ value)$deprecation$;\n");
 }
 
 void EnumFieldGenerator::
@@ -124,33 +114,37 @@ void EnumFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   printer->Print(variables_,
     "int value;\n"
-    "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+    "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
     "if ($type$_IsValid(value)) {\n"
-    "  set_$name$(static_cast< $type$ >(value));\n"
-    "} else {\n"
-    "  mutable_unknown_fields()->AddVarint($number$, value);\n"
+    "  set_$name$(static_cast< $type$ >(value));\n");
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(variables_,
+      "} else {\n"
+      "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+  }
+  printer->Print(variables_,
     "}\n");
 }
 
 void EnumFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
-    "::google::protobuf::internal::WireFormat::WriteEnum("
-      "$number$, this->$name$(), output);\n");
+    "::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
+    "  $number$, this->$name$(), output);\n");
 }
 
 void EnumFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
-    "target = ::google::protobuf::internal::WireFormat::WriteEnumToArray("
-      "$number$, this->$name$(), target);\n");
+    "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
+    "  $number$, this->$name$(), target);\n");
 }
 
 void EnumFieldGenerator::
 GenerateByteSize(io::Printer* printer) const {
   printer->Print(variables_,
     "total_size += $tag_size$ +\n"
-    "  ::google::protobuf::internal::WireFormat::EnumSize(this->$name$());\n");
+    "  ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
 }
 
 // ===================================================================
@@ -167,8 +161,7 @@ void RepeatedEnumFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField<int> $name$_;\n");
-  if (descriptor_->options().packed() &&
-      descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -177,11 +170,11 @@ GeneratePrivateMembers(io::Printer* printer) const {
 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");
+    "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
+    "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"
+    "inline $type$ $name$(int index) const$deprecation$;\n"
+    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
+    "inline void add_$name$($type$ value)$deprecation$;\n");
 }
 
 void RepeatedEnumFieldGenerator::
@@ -238,7 +231,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
           "input->PushLimit(length);\n"
       "while (input->BytesUntilLimit() > 0) {\n"
       "  int value;\n"
-      "  DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+      "  DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
       "  if ($type$_IsValid(value)) {\n"
       "    add_$name$(static_cast< $type$ >(value));\n"
       "  }\n"
@@ -247,11 +240,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
   } else {
     printer->Print(variables_,
       "int value;\n"
-      "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
       "if ($type$_IsValid(value)) {\n"
-      "  add_$name$(static_cast< $type$ >(value));\n"
-      "} else {\n"
-      "  mutable_unknown_fields()->AddVarint($number$, value);\n"
+      "  add_$name$(static_cast< $type$ >(value));\n");
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print(variables_,
+        "} else {\n"
+        "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+    }
+    printer->Print(variables_,
       "}\n");
   }
 }
@@ -262,10 +259,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
-      "  ::google::protobuf::internal::WireFormat::WriteTag("
-          "$number$, "
-          "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
-          "output);\n"
+      "  ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
+      "    $number$,\n"
+      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
+      "    output);\n"
       "  output->WriteVarint32(_$name$_cached_byte_size_);\n"
       "}\n");
   }
@@ -273,12 +270,12 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::WriteEnumNoTag("
-          "this->$name$(i), output);\n");
+      "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
+      "    this->$name$(i), output);\n");
   } else {
     printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::WriteEnum("
-          "$number$, this->$name$(i), output);\n");
+      "  ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
+      "    $number$, this->$name$(i), output);\n");
   }
   printer->Print("}\n");
 }
@@ -289,24 +286,24 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
-      "  target = ::google::protobuf::internal::WireFormat::WriteTagToArray("
-          "$number$, "
-          "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
-          "target);\n"
+      "  target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
+      "    $number$,\n"
+      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
+      "    target);\n"
       "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
-          "_$name$_cached_byte_size_, target);\n"
+      "    _$name$_cached_byte_size_, target);\n"
       "}\n");
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
-      "  target = ::google::protobuf::internal::WireFormat::WriteEnumNoTagToArray("
-          "this->$name$(i), target);\n");
+      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
+      "    this->$name$(i), target);\n");
   } else {
     printer->Print(variables_,
-      "  target = ::google::protobuf::internal::WireFormat::WriteEnumToArray("
-          "$number$, this->$name$(i), target);\n");
+      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
+      "    $number$, this->$name$(i), target);\n");
   }
   printer->Print("}\n");
 }
@@ -319,15 +316,15 @@ GenerateByteSize(io::Printer* printer) const {
   printer->Indent();
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n"
-      "  data_size += ::google::protobuf::internal::WireFormat::EnumSize(\n"
+      "  data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
       "    this->$name$(i));\n"
       "}\n");
 
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
-      "  total_size += $tag_size$ + "
-        "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
+      "  total_size += $tag_size$ +\n"
+      "    ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
       "}\n"
       "_$name$_cached_byte_size_ = data_size;\n"
       "total_size += data_size;\n");

+ 1 - 0
src/google/protobuf/compiler/cpp/cpp_extension.cc

@@ -133,6 +133,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
     vars["global_name"] = global_name;
     printer->Print(vars,
       "const ::std::string $global_name$_default($default$);\n");
+
     // Update the default to refer to the string global.
     vars["default"] = global_name + "_default";
   }

+ 19 - 0
src/google/protobuf/compiler/cpp/cpp_field.cc

@@ -33,18 +33,37 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_message_field.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
 namespace compiler {
 namespace cpp {
 
+using internal::WireFormat;
+
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             map<string, string>* variables) {
+  (*variables)["name"] = FieldName(descriptor);
+  (*variables)["index"] = SimpleItoa(descriptor->index());
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+  (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+
+  (*variables)["tag_size"] = SimpleItoa(
+    WireFormat::TagSize(descriptor->number(), descriptor->type()));
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? " DEPRECATED_PROTOBUF_FIELD" : "";
+}
+
 FieldGenerator::~FieldGenerator() {}
 
 FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)

+ 10 - 0
src/google/protobuf/compiler/cpp/cpp_field.h

@@ -35,6 +35,9 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
 
+#include <map>
+#include <string>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 
@@ -49,6 +52,13 @@ namespace protobuf {
 namespace compiler {
 namespace cpp {
 
+// Helper function: set variables in the map that are the same for all
+// field code generators.
+// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
+// 'deprecation'].
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             map<string, string>* variables);
+
 class FieldGenerator {
  public:
   FieldGenerator() {}

+ 183 - 132
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -125,13 +125,18 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
 
   // OK, it's now safe to #include other files.
   printer->Print(
-    "#include <google/protobuf/generated_message_reflection.h>\n"
+    "#include <google/protobuf/generated_message_util.h>\n"
     "#include <google/protobuf/repeated_field.h>\n"
     "#include <google/protobuf/extension_set.h>\n");
 
-  if (file_->service_count() > 0) {
+  if (HasDescriptorMethods(file_)) {
     printer->Print(
-      "#include <google/protobuf/service.h>\n");
+      "#include <google/protobuf/generated_message_reflection.h>\n");
+
+    if (file_->service_count() > 0) {
+      printer->Print(
+        "#include <google/protobuf/service.h>\n");
+    }
   }
 
   for (int i = 0; i < file_->dependency_count(); i++) {
@@ -193,19 +198,21 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   printer->Print(kThickSeparator);
   printer->Print("\n");
 
-  // Generate service definitions.
-  for (int i = 0; i < file_->service_count(); i++) {
-    if (i > 0) {
-      printer->Print("\n");
-      printer->Print(kThinSeparator);
-      printer->Print("\n");
+  if (HasDescriptorMethods(file_)) {
+    // Generate service definitions.
+    for (int i = 0; i < file_->service_count(); i++) {
+      if (i > 0) {
+        printer->Print("\n");
+        printer->Print(kThinSeparator);
+        printer->Print("\n");
+      }
+      service_generators_[i]->GenerateDeclarations(printer);
     }
-    service_generators_[i]->GenerateDeclarations(printer);
-  }
 
-  printer->Print("\n");
-  printer->Print(kThickSeparator);
-  printer->Print("\n");
+    printer->Print("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
+  }
 
   // Declare extension identifiers.
   for (int i = 0; i < file_->extension_count(); i++) {
@@ -228,6 +235,30 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   // Close up namespace.
   GenerateNamespaceClosers(printer);
 
+  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+  if (HasDescriptorMethods(file_)) {
+    // The SWIG conditional is to avoid a null-pointer dereference
+    // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
+    //   namespace X { void Y<Z::W>(); }
+    // which appears in GetEnumDescriptor() specializations.
+    printer->Print(
+        "\n"
+        "#ifndef SWIG\n"
+        "namespace google {\nnamespace protobuf {\n"
+        "\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    printer->Print(
+        "\n"
+        "}  // namespace google\n}  // namespace protobuf\n"
+        "#endif  // SWIG\n"
+        "\n");
+  }
+
   printer->Print(
     "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
     "filename_identifier", filename_identifier);
@@ -237,40 +268,52 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "\n"
+    // The generated code calls accessors that might be deprecated. We don't
+    // want the compiler to warn in generated code.
+    "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
     "#include \"$basename$.pb.h\"\n"
+
     "#include <google/protobuf/stubs/once.h>\n"
-    "#include <google/protobuf/descriptor.h>\n"
     "#include <google/protobuf/io/coded_stream.h>\n"
-    "#include <google/protobuf/reflection_ops.h>\n"
-    "#include <google/protobuf/wire_format_inl.h>\n",
+    "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "basename", StripProto(file_->name()));
 
+  if (HasDescriptorMethods(file_)) {
+    printer->Print(
+      "#include <google/protobuf/descriptor.h>\n"
+      "#include <google/protobuf/reflection_ops.h>\n"
+      "#include <google/protobuf/wire_format.h>\n");
+  }
+
   GenerateNamespaceOpeners(printer);
 
-  printer->Print(
-    "\n"
-    "namespace {\n"
-    "\n");
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateDescriptorDeclarations(printer);
-  }
-  for (int i = 0; i < file_->enum_type_count(); i++) {
+  if (HasDescriptorMethods(file_)) {
     printer->Print(
-      "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
-      "name", ClassName(file_->enum_type(i), false));
-  }
-  for (int i = 0; i < file_->service_count(); i++) {
+      "\n"
+      "namespace {\n"
+      "\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateDescriptorDeclarations(printer);
+    }
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      printer->Print(
+        "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
+        "name", ClassName(file_->enum_type(i), false));
+    }
+    for (int i = 0; i < file_->service_count(); i++) {
+      printer->Print(
+        "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
+        "name", file_->service(i)->name());
+    }
+
     printer->Print(
-      "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
-      "name", file_->service(i)->name());
+      "\n"
+      "}  // namespace\n"
+      "\n");
   }
 
-  printer->Print(
-    "\n"
-    "}  // namespace\n"
-    "\n");
-
-  // Define our externally-visible BuildDescriptors() function.
+  // Define our externally-visible BuildDescriptors() function.  (For the lite
+  // library, all this does is initialize default instances.)
   GenerateBuildDescriptors(printer);
 
   // Generate enums.
@@ -286,12 +329,14 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     message_generators_[i]->GenerateClassMethods(printer);
   }
 
-  // Generate services.
-  for (int i = 0; i < file_->service_count(); i++) {
-    if (i == 0) printer->Print("\n");
-    printer->Print(kThickSeparator);
-    printer->Print("\n");
-    service_generators_[i]->GenerateImplementation(printer);
+  if (HasDescriptorMethods(file_)) {
+    // Generate services.
+    for (int i = 0; i < file_->service_count(); i++) {
+      if (i == 0) printer->Print("\n");
+      printer->Print(kThickSeparator);
+      printer->Print("\n");
+      service_generators_[i]->GenerateImplementation(printer);
+    }
   }
 
   // Define extensions.
@@ -317,80 +362,84 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
   // anyone calls descriptor() or GetReflection() on one of the types defined
   // in the file.
 
-  printer->Print(
-    "\n"
-    "void $assigndescriptorsname$() {\n",
-    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
-  printer->Indent();
-
-  // Make sure the file has found its way into the pool.  If a descriptor
-  // is requested *during* static init then AddDescriptors() may not have
-  // been called yet, so we call it manually.  Note that it's fine if
-  // AddDescriptors() is called multiple times.
-  printer->Print(
-    "$adddescriptorsname$();\n",
-    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
+  // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
+  // and we only use AddDescriptors() to allocate default instances.
+  if (HasDescriptorMethods(file_)) {
+    printer->Print(
+      "\n"
+      "void $assigndescriptorsname$() {\n",
+      "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+    printer->Indent();
+
+    // Make sure the file has found its way into the pool.  If a descriptor
+    // is requested *during* static init then AddDescriptors() may not have
+    // been called yet, so we call it manually.  Note that it's fine if
+    // AddDescriptors() is called multiple times.
+    printer->Print(
+      "$adddescriptorsname$();\n",
+      "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
 
-  // Get the file's descriptor from the pool.
-  printer->Print(
-    "const ::google::protobuf::FileDescriptor* file =\n"
-    "  ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
-    "    \"$filename$\");\n"
-    // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
-    // being unused when compiling an empty .proto file.
-    "GOOGLE_CHECK(file != NULL);\n",
-    "filename", file_->name());
-
-  // Go through all the stuff defined in this file and generated code to
-  // assign the global descriptor pointers based on the file descriptor.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateDescriptorInitializer(printer, i);
-  }
-  for (int i = 0; i < file_->enum_type_count(); i++) {
-    enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
-  }
-  for (int i = 0; i < file_->service_count(); i++) {
-    service_generators_[i]->GenerateDescriptorInitializer(printer, i);
-  }
+    // Get the file's descriptor from the pool.
+    printer->Print(
+      "const ::google::protobuf::FileDescriptor* file =\n"
+      "  ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
+      "    \"$filename$\");\n"
+      // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
+      // being unused when compiling an empty .proto file.
+      "GOOGLE_CHECK(file != NULL);\n",
+      "filename", file_->name());
+
+    // Go through all the stuff defined in this file and generated code to
+    // assign the global descriptor pointers based on the file descriptor.
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateDescriptorInitializer(printer, i);
+    }
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
+    }
+    for (int i = 0; i < file_->service_count(); i++) {
+      service_generators_[i]->GenerateDescriptorInitializer(printer, i);
+    }
 
-  printer->Outdent();
-  printer->Print(
-    "}\n"
-    "\n");
+    printer->Outdent();
+    printer->Print(
+      "}\n"
+      "\n");
 
-  // -----------------------------------------------------------------
+    // ---------------------------------------------------------------
 
-  // protobuf_AssignDescriptorsOnce():  The first time it is called, calls
-  // AssignDescriptors().  All later times, waits for the first call to
-  // complete and then returns.
-  printer->Print(
-    "namespace {\n"
-    "\n"
-    "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
-    "inline void protobuf_AssignDescriptorsOnce() {\n"
-    "  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
-    "                 &$assigndescriptorsname$);\n"
-    "}\n"
-    "\n",
-    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+    // protobuf_AssignDescriptorsOnce():  The first time it is called, calls
+    // AssignDescriptors().  All later times, waits for the first call to
+    // complete and then returns.
+    printer->Print(
+      "namespace {\n"
+      "\n"
+      "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
+      "inline void protobuf_AssignDescriptorsOnce() {\n"
+      "  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
+      "                 &$assigndescriptorsname$);\n"
+      "}\n"
+      "\n",
+      "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+
+    // protobuf_RegisterTypes():  Calls
+    // MessageFactory::InternalRegisterGeneratedType() for each message type.
+    printer->Print(
+      "void protobuf_RegisterTypes(const ::std::string&) {\n"
+      "  protobuf_AssignDescriptorsOnce();\n");
+    printer->Indent();
 
-  // protobuf_RegisterTypes():  Calls
-  // MessageFactory::InternalRegisterGeneratedType() for each message type.
-  printer->Print(
-    "void protobuf_RegisterTypes() {\n"
-    "  protobuf_AssignDescriptorsOnce();\n");
-  printer->Indent();
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateTypeRegistrations(printer);
+    }
 
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateTypeRegistrations(printer);
+    printer->Outdent();
+    printer->Print(
+      "}\n"
+      "\n"
+      "}  // namespace\n");
   }
 
-  printer->Outdent();
-  printer->Print(
-    "}\n"
-    "\n"
-    "}  // namespace\n");
-
   // -----------------------------------------------------------------
 
   // ShutdownFile():  Deletes descriptors, default instances, etc. on shutdown.
@@ -442,32 +491,34 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
       "name", GlobalAddDescriptorsName(dependency->name()));
   }
 
-  // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
-  // and embed it as a string literal, which is parsed and built into real
-  // descriptors at initialization time.
-  FileDescriptorProto file_proto;
-  file_->CopyTo(&file_proto);
-  string file_data;
-  file_proto.SerializeToString(&file_data);
+  if (HasDescriptorMethods(file_)) {
+    // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
+    // and embed it as a string literal, which is parsed and built into real
+    // descriptors at initialization time.
+    FileDescriptorProto file_proto;
+    file_->CopyTo(&file_proto);
+    string file_data;
+    file_proto.SerializeToString(&file_data);
 
-  printer->Print(
-    "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
+    printer->Print(
+      "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
 
-  // Only write 40 bytes per line.
-  static const int kBytesPerLine = 40;
-  for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
-    printer->Print("\n  \"$data$\"",
-      "data", CEscape(file_data.substr(i, kBytesPerLine)));
-  }
-  printer->Print(
-    ", $size$);\n",
-    "size", SimpleItoa(file_data.size()));
+    // Only write 40 bytes per line.
+    static const int kBytesPerLine = 40;
+    for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+      printer->Print("\n  \"$data$\"",
+        "data", CEscape(file_data.substr(i, kBytesPerLine)));
+    }
+    printer->Print(
+      ", $size$);\n",
+      "size", SimpleItoa(file_data.size()));
 
-  // Call MessageFactory::InternalRegisterGeneratedFile().
-  printer->Print(
-    "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
-    "  \"$filename$\", &protobuf_RegisterTypes);\n",
-    "filename", file_->name());
+    // Call MessageFactory::InternalRegisterGeneratedFile().
+    printer->Print(
+      "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
+      "  \"$filename$\", &protobuf_RegisterTypes);\n",
+      "filename", file_->name());
+  }
 
   // Allocate and initialize default instances.  This can't be done lazily
   // since default instances are returned by simple accessors and are used with

+ 1 - 28
src/google/protobuf/compiler/cpp/cpp_generator.cc

@@ -42,39 +42,12 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
 namespace compiler {
 namespace cpp {
 
-namespace {
-
-// Parses a set of comma-delimited name/value pairs, e.g.:
-//   "foo=bar,baz,qux=corge"
-// parses to the pairs:
-//   ("foo", "bar"), ("baz", ""), ("qux", "corge")
-void ParseOptions(const string& text, vector<pair<string, string> >* output) {
-  vector<string> parts;
-  SplitStringUsing(text, ",", &parts);
-
-  for (int i = 0; i < parts.size(); i++) {
-    string::size_type equals_pos = parts[i].find_first_of('=');
-    pair<string, string> value;
-    if (equals_pos == string::npos) {
-      value.first = parts[i];
-      value.second = "";
-    } else {
-      value.first = parts[i].substr(0, equals_pos);
-      value.second = parts[i].substr(equals_pos + 1);
-    }
-    output->push_back(value);
-  }
-}
-
-}  // namespace
-
 CppGenerator::CppGenerator() {}
 CppGenerator::~CppGenerator() {}
 
@@ -83,7 +56,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
                             OutputDirectory* output_directory,
                             string* error) const {
   vector<pair<string, string> > options;
-  ParseOptions(parameter, &options);
+  ParseGeneratorParameter(parameter, &options);
 
   // -----------------------------------------------------------------
   // parse generator options

+ 12 - 1
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -152,7 +152,18 @@ string FieldName(const FieldDescriptor* field) {
 
 string FieldConstantName(const FieldDescriptor *field) {
   string field_name = UnderscoresToCamelCase(field->name(), true);
-  return "k" + field_name + "FieldNumber";
+  string result = "k" + field_name + "FieldNumber";
+
+  if (!field->is_extension() &&
+      field->containing_type()->FindFieldByCamelcaseName(
+        field->camelcase_name()) != field) {
+    // This field's camelcase name is not unique.  As a hack, add the field
+    // number to the constant name.  This makes the constant rather useless,
+    // but what can we do?
+    result += "_" + SimpleItoa(field->number());
+  }
+
+  return result;
 }
 
 string StripProto(const string& filename) {

+ 29 - 0
src/google/protobuf/compiler/cpp/cpp_helpers.h

@@ -37,6 +37,7 @@
 
 #include <string>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
@@ -105,6 +106,34 @@ string GlobalAssignDescriptorsName(const string& filename);
 // Return the name of the ShutdownFile() function for a given file.
 string GlobalShutdownFileName(const string& filename);
 
+// Do message classes in this file keep track of unknown fields?
+inline const bool HasUnknownFields(const FileDescriptor *file) {
+  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
+}
+
+// Does this file have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+inline const bool HasGeneratedMethods(const FileDescriptor *file) {
+  return file->options().optimize_for() != FileOptions::CODE_SIZE;
+}
+
+// Do message classes in this file have descriptor and refelction methods?
+inline const bool HasDescriptorMethods(const FileDescriptor *file) {
+  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
+}
+
+// Should string fields in this file verify that their contents are UTF-8?
+inline const bool HasUtf8Verification(const FileDescriptor* file) {
+  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
+}
+
+// Should we generate a separate, super-optimized code path for serializing to
+// flat arrays?  We don't do this in Lite mode because we'd rather reduce code
+// size.
+inline const bool HasFastArraySerialization(const FileDescriptor* file) {
+  return file->options().optimize_for() == FileOptions::SPEED;
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf

+ 335 - 188
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -34,14 +34,17 @@
 
 #include <algorithm>
 #include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <vector>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
+#include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/descriptor.pb.h>
 
 namespace google {
@@ -50,6 +53,7 @@ namespace compiler {
 namespace cpp {
 
 using internal::WireFormat;
+using internal::WireFormatLite;
 
 namespace {
 
@@ -195,6 +199,16 @@ GenerateEnumDefinitions(io::Printer* printer) {
   }
 }
 
+void MessageGenerator::
+GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    nested_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+  }
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+  }
+}
+
 void MessageGenerator::
 GenerateFieldAccessorDeclarations(io::Printer* printer) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -203,17 +217,16 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
     PrintFieldComment(printer, field);
 
     map<string, string> vars;
-    vars["name"] = FieldName(field);
+    SetCommonFieldVariables(field, &vars);
     vars["constant_name"] = FieldConstantName(field);
-    vars["number"] = SimpleItoa(field->number());
 
     if (field->is_repeated()) {
-      printer->Print(vars, "inline int $name$_size() const;\n");
+      printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
     } else {
-      printer->Print(vars, "inline bool has_$name$() const;\n");
+      printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
     }
 
-    printer->Print(vars, "inline void clear_$name$();\n");
+    printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
     printer->Print(vars, "static const int $constant_name$ = $number$;\n");
 
     // Generate type-specific accessor declarations.
@@ -241,9 +254,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
     PrintFieldComment(printer, field);
 
     map<string, string> vars;
-    vars["name"] = FieldName(field);
-    vars["index"] = SimpleItoa(field->index());
-    vars["classname"] = classname_;
+    SetCommonFieldVariables(field, &vars);
 
     // Generate has_$name$() or $name$_size().
     if (field->is_repeated()) {
@@ -297,9 +308,11 @@ GenerateClassDefinition(io::Printer* printer) {
   } else {
     vars["dllexport"] = dllexport_decl_ + " ";
   }
+  vars["superclass"] = HasDescriptorMethods(descriptor_->file()) ?
+                       "Message" : "MessageLite";
 
   printer->Print(vars,
-    "class $dllexport$$classname$ : public ::google::protobuf::Message {\n"
+    "class $dllexport$$classname$ : public ::google::protobuf::$superclass$ {\n"
     " public:\n");
   printer->Indent();
 
@@ -313,16 +326,28 @@ GenerateClassDefinition(io::Printer* printer) {
     "  CopyFrom(from);\n"
     "  return *this;\n"
     "}\n"
-    "\n"
-    "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
-    "  return _unknown_fields_;\n"
-    "}\n"
-    "\n"
-    "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
-    "  return &_unknown_fields_;\n"
-    "}\n"
-    "\n"
-    "static const ::google::protobuf::Descriptor* descriptor();\n"
+    "\n");
+
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(
+      "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
+      "  return _unknown_fields_;\n"
+      "}\n"
+      "\n"
+      "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
+      "  return &_unknown_fields_;\n"
+      "}\n"
+      "\n");
+  }
+
+  // Only generate this member if it's not disabled.
+  if (HasDescriptorMethods(descriptor_->file()) &&
+      !descriptor_->options().no_standard_descriptor_accessor()) {
+    printer->Print(vars,
+      "static const ::google::protobuf::Descriptor* descriptor();\n");
+  }
+
+  printer->Print(vars,
     "static const $classname$& default_instance();\n"
     "void Swap($classname$* other);\n"
     "\n"
@@ -330,28 +355,29 @@ GenerateClassDefinition(io::Printer* printer) {
     "\n"
     "$classname$* New() const;\n");
 
-  if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (HasGeneratedMethods(descriptor_->file())) {
+    if (HasDescriptorMethods(descriptor_->file())) {
+      printer->Print(vars,
+        "void CopyFrom(const ::google::protobuf::Message& from);\n"
+        "void MergeFrom(const ::google::protobuf::Message& from);\n");
+    } else {
+      printer->Print(vars,
+        "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);\n");
+    }
+
     printer->Print(vars,
-      "void CopyFrom(const ::google::protobuf::Message& from);\n"
-      "void MergeFrom(const ::google::protobuf::Message& from);\n"
       "void CopyFrom(const $classname$& from);\n"
       "void MergeFrom(const $classname$& from);\n"
       "void Clear();\n"
-      "bool IsInitialized() const;\n");
-
-    if (!descriptor_->options().message_set_wire_format()) {
-      // For message_set_wire_format, we don't generate parsing or
-      // serialization code even if optimize_for = SPEED, since MessageSet
-      // encoding is somewhat more complicated than normal extension encoding
-      // and we'd like to avoid having to implement it in multiple places.
-      // WireFormat's implementation is probably good enough.
-      printer->Print(vars,
-        "\n"
-        "int ByteSize() const;\n"
-        "bool MergePartialFromCodedStream(\n"
-        "    ::google::protobuf::io::CodedInputStream* input);\n"
-        "void SerializeWithCachedSizes(\n"
-        "    ::google::protobuf::io::CodedOutputStream* output) const;\n"
+      "bool IsInitialized() const;\n"
+      "\n"
+      "int ByteSize() const;\n"
+      "bool MergePartialFromCodedStream(\n"
+      "    ::google::protobuf::io::CodedInputStream* input);\n"
+      "void SerializeWithCachedSizes(\n"
+      "    ::google::protobuf::io::CodedOutputStream* output) const;\n");
+    if (HasFastArraySerialization(descriptor_->file())) {
+      printer->Print(
         "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
     }
   }
@@ -363,10 +389,19 @@ GenerateClassDefinition(io::Printer* printer) {
     "void SharedDtor();\n"
     "void SetCachedSize(int size) const { _cached_size_ = size; }\n"
     "public:\n"
-    "\n"
-    "const ::google::protobuf::Descriptor* GetDescriptor() const;\n"
-    "const ::google::protobuf::Reflection* GetReflection() const;\n"
-    "\n"
+    "\n");
+
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(
+      "::google::protobuf::Metadata GetMetadata() const;\n"
+      "\n");
+  } else {
+    printer->Print(
+      "::std::string GetTypeName() const;\n"
+      "\n");
+  }
+
+  printer->Print(
     "// nested types ----------------------------------------------------\n"
     "\n");
 
@@ -411,9 +446,13 @@ GenerateClassDefinition(io::Printer* printer) {
       "::google::protobuf::internal::ExtensionSet _extensions_;\n");
   }
 
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(
+      "::google::protobuf::UnknownFieldSet _unknown_fields_;\n");
+  }
+
   // TODO(kenton):  Make _cached_size_ an atomic<int> when C++ supports it.
   printer->Print(
-    "::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
     "mutable int _cached_size_;\n"
     "\n");
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -431,7 +470,8 @@ GenerateClassDefinition(io::Printer* printer) {
       GlobalAddDescriptorsName(descriptor_->file()->name()));
   printer->Print(
     "friend void $assigndescriptorsname$();\n"
-    "friend void $shutdownfilename$();\n",
+    "friend void $shutdownfilename$();\n"
+    "\n",
     "assigndescriptorsname",
       GlobalAssignDescriptorsName(descriptor_->file()->name()),
     "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name()));
@@ -605,10 +645,15 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
 void MessageGenerator::
 GenerateShutdownCode(io::Printer* printer) {
   printer->Print(
-    "delete $classname$::default_instance_;\n"
-    "delete $classname$_reflection_;\n",
+    "delete $classname$::default_instance_;\n",
     "classname", classname_);
 
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(
+      "delete $classname$_reflection_;\n",
+      "classname", classname_);
+  }
+
   // Handle nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     nested_generators_[i]->GenerateShutdownCode(printer);
@@ -655,29 +700,24 @@ GenerateClassMethods(io::Printer* printer) {
   GenerateStructors(printer);
   printer->Print("\n");
 
-  if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (HasGeneratedMethods(descriptor_->file())) {
     GenerateClear(printer);
     printer->Print("\n");
 
-    if (!descriptor_->options().message_set_wire_format()) {
-      // For message_set_wire_format, we don't generate parsing or
-      // serialization code even if optimize_for = SPEED, since MessageSet
-      // encoding is somewhat more complicated than normal extension encoding
-      // and we'd like to avoid having to implement it in multiple places.
-      // WireFormat's implementation is probably good enough.
-      GenerateMergeFromCodedStream(printer);
-      printer->Print("\n");
+    GenerateMergeFromCodedStream(printer);
+    printer->Print("\n");
 
-      GenerateSerializeWithCachedSizes(printer);
-      printer->Print("\n");
+    GenerateSerializeWithCachedSizes(printer);
+    printer->Print("\n");
 
+    if (HasFastArraySerialization(descriptor_->file())) {
       GenerateSerializeWithCachedSizesToArray(printer);
       printer->Print("\n");
-
-      GenerateByteSize(printer);
-      printer->Print("\n");
     }
 
+    GenerateByteSize(printer);
+    printer->Print("\n");
+
     GenerateMergeFrom(printer);
     printer->Print("\n");
 
@@ -691,16 +731,26 @@ GenerateClassMethods(io::Printer* printer) {
   GenerateSwap(printer);
   printer->Print("\n");
 
-  printer->Print(
-    "const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n"
-    "  return descriptor();\n"
-    "}\n"
-    "\n"
-    "const ::google::protobuf::Reflection* $classname$::GetReflection() const {\n"
-    "  protobuf_AssignDescriptorsOnce();\n"
-    "  return $classname$_reflection_;\n"
-    "}\n",
-    "classname", classname_);
+  if (HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(
+      "::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
+      "  protobuf_AssignDescriptorsOnce();\n"
+      "  ::google::protobuf::Metadata metadata;\n"
+      "  metadata.descriptor = $classname$_descriptor_;\n"
+      "  metadata.reflection = $classname$_reflection_;\n"
+      "  return metadata;\n"
+      "}\n"
+      "\n",
+      "classname", classname_);
+  } else {
+    printer->Print(
+      "::std::string $classname$::GetTypeName() const {\n"
+      "  return \"$type_name$\";\n"
+      "}\n"
+      "\n",
+      "classname", classname_,
+      "type_name", descriptor_->full_name());
+  }
 }
 
 void MessageGenerator::
@@ -723,18 +773,6 @@ GenerateOffsets(io::Printer* printer) {
   printer->Print("};\n");
 }
 
-void MessageGenerator::
-GenerateInitializerList(io::Printer* printer) {
-  printer->Indent();
-  printer->Indent();
-
-  printer->Print(
-    "::google::protobuf::Message()");
-
-  printer->Outdent();
-  printer->Outdent();
-}
-
 void MessageGenerator::
 GenerateSharedConstructorCode(io::Printer* printer) {
   printer->Print(
@@ -797,17 +835,14 @@ void MessageGenerator::
 GenerateStructors(io::Printer* printer) {
   // Generate the default constructor.
   printer->Print(
-      "$classname$::$classname$()\n"
-      "  : ",
-      "classname", classname_);
-  GenerateInitializerList(printer);
-  printer->Print(" {\n"
+    "$classname$::$classname$() {\n"
     "  SharedCtor();\n"
-    "}\n");
+    "}\n",
+    "classname", classname_);
 
   printer->Print(
     "\n"
-    "void $classname$::InitAsDefaultInstance() {",
+    "void $classname$::InitAsDefaultInstance() {\n",
     "classname", classname_);
 
   // The default instance needs all of its embedded message pointers
@@ -833,15 +868,12 @@ GenerateStructors(io::Printer* printer) {
 
   // Generate the copy constructor.
   printer->Print(
-      "$classname$::$classname$(const $classname$& from)\n"
-      "  : ",
-      "classname", classname_);
-  GenerateInitializerList(printer);
-  printer->Print(" {\n"
+    "$classname$::$classname$(const $classname$& from) {\n"
     "  SharedCtor();\n"
     "  MergeFrom(from);\n"
     "}\n"
-    "\n");
+    "\n",
+    "classname", classname_);
 
   // Generate the shared constructor code.
   GenerateSharedConstructorCode(printer);
@@ -857,12 +889,21 @@ GenerateStructors(io::Printer* printer) {
   // Generate the shared destructor code.
   GenerateSharedDestructorCode(printer);
 
+  // Only generate this member if it's not disabled.
+  if (HasDescriptorMethods(descriptor_->file()) &&
+      !descriptor_->options().no_standard_descriptor_accessor()) {
+    printer->Print(
+      "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
+      "  protobuf_AssignDescriptorsOnce();\n"
+      "  return $classname$_descriptor_;\n"
+      "}\n"
+      "\n",
+      "classname", classname_,
+      "adddescriptorsname",
+      GlobalAddDescriptorsName(descriptor_->file()->name()));
+  }
+
   printer->Print(
-    "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
-    "  protobuf_AssignDescriptorsOnce();\n"
-    "  return $classname$_descriptor_;\n"
-    "}\n"
-    "\n"
     "const $classname$& $classname$::default_instance() {\n"
     "  if (default_instance_ == NULL) $adddescriptorsname$();"
     "  return *default_instance_;\n"
@@ -951,8 +992,12 @@ GenerateClear(io::Printer* printer) {
   }
 
   printer->Print(
-    "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"
-    "mutable_unknown_fields()->Clear();\n");
+    "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(
+      "mutable_unknown_fields()->Clear();\n");
+  }
 
   printer->Outdent();
   printer->Print("}\n");
@@ -967,7 +1012,7 @@ GenerateSwap(io::Printer* printer) {
   printer->Print("if (other != this) {\n");
   printer->Indent();
 
-  if ( descriptor_->file()->options().optimize_for() == FileOptions::SPEED ) {
+  if (HasGeneratedMethods(descriptor_->file())) {
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* field = descriptor_->field(i);
       field_generators_.get(field).GenerateSwappingCode(printer);
@@ -978,7 +1023,9 @@ GenerateSwap(io::Printer* printer) {
                      "i", SimpleItoa(i));
     }
 
-    printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+    }
     printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
     if (descriptor_->extension_range_count() > 0) {
       printer->Print("_extensions_.Swap(&other->_extensions_);\n");
@@ -987,7 +1034,6 @@ GenerateSwap(io::Printer* printer) {
     printer->Print("GetReflection()->Swap(this, other);");
   }
 
-
   printer->Outdent();
   printer->Print("}\n");
   printer->Outdent();
@@ -996,31 +1042,42 @@ GenerateSwap(io::Printer* printer) {
 
 void MessageGenerator::
 GenerateMergeFrom(io::Printer* printer) {
-  // Generate the generalized MergeFrom (aka that which takes in the Message
-  // base class as a parameter).
-  printer->Print(
-    "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
-    "  GOOGLE_CHECK_NE(&from, this);\n",
-    "classname", classname_);
-  printer->Indent();
+  if (HasDescriptorMethods(descriptor_->file())) {
+    // Generate the generalized MergeFrom (aka that which takes in the Message
+    // base class as a parameter).
+    printer->Print(
+      "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
+      "  GOOGLE_CHECK_NE(&from, this);\n",
+      "classname", classname_);
+    printer->Indent();
 
-  // Cast the message to the proper type. If we find that the message is
-  // *not* of the proper type, we can still call Merge via the reflection
-  // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
-  // for each message.
-  printer->Print(
-    "const $classname$* source =\n"
-    "  ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
-    "    &from);\n"
-    "if (source == NULL) {\n"
-    "  ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
-    "} else {\n"
-    "  MergeFrom(*source);\n"
-    "}\n",
-    "classname", classname_);
+    // Cast the message to the proper type. If we find that the message is
+    // *not* of the proper type, we can still call Merge via the reflection
+    // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
+    // for each message.
+    printer->Print(
+      "const $classname$* source =\n"
+      "  ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
+      "    &from);\n"
+      "if (source == NULL) {\n"
+      "  ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
+      "} else {\n"
+      "  MergeFrom(*source);\n"
+      "}\n",
+      "classname", classname_);
 
-  printer->Outdent();
-  printer->Print("}\n\n");
+    printer->Outdent();
+    printer->Print("}\n\n");
+  } else {
+    // Generate CheckTypeAndMergeFrom().
+    printer->Print(
+      "void $classname$::CheckTypeAndMergeFrom(\n"
+      "    const ::google::protobuf::MessageLite& from) {\n"
+      "  MergeFrom(*::google::protobuf::down_cast<const $classname$*>(&from));\n"
+      "}\n"
+      "\n",
+      "classname", classname_);
+  }
 
   // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
   printer->Print(
@@ -1082,8 +1139,10 @@ GenerateMergeFrom(io::Printer* printer) {
     printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
   }
 
-  printer->Print(
-    "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(
+      "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
+  }
 
   printer->Outdent();
   printer->Print("}\n");
@@ -1091,20 +1150,22 @@ GenerateMergeFrom(io::Printer* printer) {
 
 void MessageGenerator::
 GenerateCopyFrom(io::Printer* printer) {
-  // Generate the generalized CopyFrom (aka that which takes in the Message
-  // base class as a parameter).
-  printer->Print(
-    "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
-    "classname", classname_);
-  printer->Indent();
+  if (HasDescriptorMethods(descriptor_->file())) {
+    // Generate the generalized CopyFrom (aka that which takes in the Message
+    // base class as a parameter).
+    printer->Print(
+      "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
+      "classname", classname_);
+    printer->Indent();
 
-  printer->Print(
-    "if (&from == this) return;\n"
-    "Clear();\n"
-    "MergeFrom(from);\n");
+    printer->Print(
+      "if (&from == this) return;\n"
+      "Clear();\n"
+      "MergeFrom(from);\n");
 
-  printer->Outdent();
-  printer->Print("}\n\n");
+    printer->Outdent();
+    printer->Print("}\n\n");
+  }
 
   // Generate the class-specific CopyFrom.
   printer->Print(
@@ -1123,6 +1184,18 @@ GenerateCopyFrom(io::Printer* printer) {
 
 void MessageGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) {
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    printer->Print(
+      "bool $classname$::MergePartialFromCodedStream(\n"
+      "    ::google::protobuf::io::CodedInputStream* input) {\n"
+      "  return _extensions_.ParseMessageSet(input, default_instance_,\n"
+      "                                      mutable_unknown_fields());\n"
+      "}\n",
+      "classname", classname_);
+    return;
+  }
+
   printer->Print(
     "bool $classname$::MergePartialFromCodedStream(\n"
     "    ::google::protobuf::io::CodedInputStream* input) {\n"
@@ -1144,7 +1217,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
     // creates a jump table that is 8x larger and sparser, and meanwhile the
     // if()s are highly predictable.
     printer->Print(
-      "switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {\n");
+      "switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n");
 
     printer->Indent();
 
@@ -1158,8 +1231,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
 
       printer->Print(
         "case $number$: {\n"
-        "  if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=\n"
-        "      ::google::protobuf::internal::WireFormat::WIRETYPE_$wiretype$) {\n"
+        "  if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) !=\n"
+        "      ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n"
         "    goto handle_uninterpreted;\n"
         "  }\n",
         "number", SimpleItoa(field->number()),
@@ -1214,8 +1287,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
 
   // Is this an end-group tag?  If so, this must be the end of the message.
   printer->Print(
-    "if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==\n"
-    "    ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {\n"
+    "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
+    "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
     "  return true;\n"
     "}\n");
 
@@ -1228,10 +1301,10 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
         descriptor_->extension_range(i);
       if (i > 0) printer->Print(" ||\n    ");
 
-      uint32 start_tag = WireFormat::MakeTag(
-        range->start, static_cast<WireFormat::WireType>(0));
-      uint32 end_tag = WireFormat::MakeTag(
-        range->end, static_cast<WireFormat::WireType>(0));
+      uint32 start_tag = WireFormatLite::MakeTag(
+        range->start, static_cast<WireFormatLite::WireType>(0));
+      uint32 end_tag = WireFormatLite::MakeTag(
+        range->end, static_cast<WireFormatLite::WireType>(0));
 
       if (range->end > FieldDescriptor::kMaxNumber) {
         printer->Print(
@@ -1244,17 +1317,29 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
           "end", SimpleItoa(end_tag));
       }
     }
-    printer->Print(") {\n"
-      "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
-      "                              mutable_unknown_fields()));\n"
+    printer->Print(") {\n");
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print(
+        "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
+        "                              mutable_unknown_fields()));\n");
+    } else {
+      printer->Print(
+        "  DO_(_extensions_.ParseField(tag, input, default_instance_));\n");
+    }
+    printer->Print(
       "  continue;\n"
       "}\n");
   }
 
   // We really don't recognize this tag.  Skip it.
-  printer->Print(
-    "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
-    "      input, tag, mutable_unknown_fields()));\n");
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print(
+      "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
+      "      input, tag, mutable_unknown_fields()));\n");
+  } else {
+    printer->Print(
+      "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
+  }
 
   if (descriptor_->field_count() > 0) {
     printer->Print("break;\n");
@@ -1319,21 +1404,41 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
 
 void MessageGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) {
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    printer->Print(
+      "void $classname$::SerializeWithCachedSizes(\n"
+      "    ::google::protobuf::io::CodedOutputStream* output) const {\n"
+      "  _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
+      "classname", classname_);
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print(
+        "  ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
+        "      unknown_fields(), output);\n");
+    }
+    printer->Print(
+      "}\n");
+    return;
+  }
+
   printer->Print(
     "void $classname$::SerializeWithCachedSizes(\n"
     "    ::google::protobuf::io::CodedOutputStream* output) const {\n",
     "classname", classname_);
   printer->Indent();
 
-  printer->Print(
-    "::google::protobuf::uint8* raw_buffer = "
-      "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n"
-    "if (raw_buffer != NULL) {\n"
-    "  $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n"
-    "  return;\n"
-    "}\n"
-    "\n",
-    "classname", classname_);
+  if (HasFastArraySerialization(descriptor_->file())) {
+    printer->Print(
+      "::google::protobuf::uint8* raw_buffer = "
+        "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n"
+      "if (raw_buffer != NULL) {\n"
+      "  $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n"
+      "  return;\n"
+      "}\n"
+      "\n",
+      "classname", classname_);
+  }
+
   GenerateSerializeWithCachedSizesBody(printer, false);
 
   printer->Outdent();
@@ -1343,6 +1448,26 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
 
 void MessageGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    printer->Print(
+      "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
+      "    ::google::protobuf::uint8* target) const {\n"
+      "  target =\n"
+      "      _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
+      "classname", classname_);
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print(
+        "  target = ::google::protobuf::internal::WireFormat::\n"
+        "             SerializeUnknownMessageSetItemsToArray(\n"
+        "               unknown_fields(), target);\n");
+    }
+    printer->Print(
+      "  return target;\n"
+      "}\n");
+    return;
+  }
+
   printer->Print(
     "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
     "    ::google::protobuf::uint8* target) const {\n",
@@ -1389,26 +1514,46 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
     }
   }
 
-  printer->Print("if (!unknown_fields().empty()) {\n");
-  printer->Indent();
-  if (to_array) {
-    printer->Print(
-      "target = "
-          "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
-      "    unknown_fields(), target);\n");
-  } else {
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print("if (!unknown_fields().empty()) {\n");
+    printer->Indent();
+    if (to_array) {
+      printer->Print(
+        "target = "
+            "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
+        "    unknown_fields(), target);\n");
+    } else {
+      printer->Print(
+        "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+        "    unknown_fields(), output);\n");
+    }
+    printer->Outdent();
+
     printer->Print(
-      "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
-      "    unknown_fields(), output);\n");
+      "}\n");
   }
-  printer->Outdent();
-
-  printer->Print(
-    "}\n");
 }
 
 void MessageGenerator::
 GenerateByteSize(io::Printer* printer) {
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    printer->Print(
+      "int $classname$::ByteSize() const {\n"
+      "  int total_size = _extensions_.MessageSetByteSize();\n",
+      "classname", classname_);
+    if (HasUnknownFields(descriptor_->file())) {
+      printer->Print(
+        "  total_size += ::google::protobuf::internal::WireFormat::\n"
+        "      ComputeUnknownMessageSetItemsSize(unknown_fields());\n");
+    }
+    printer->Print(
+      "  _cached_size_ = total_size;\n"
+      "  return total_size;\n"
+      "}\n");
+    return;
+  }
+
   printer->Print(
     "int $classname$::ByteSize() const {\n",
     "classname", classname_);
@@ -1478,14 +1623,16 @@ GenerateByteSize(io::Printer* printer) {
       "\n");
   }
 
-  printer->Print("if (!unknown_fields().empty()) {\n");
-  printer->Indent();
-  printer->Print(
-    "total_size +=\n"
-    "  ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
-    "    unknown_fields());\n");
-  printer->Outdent();
-  printer->Print("}\n");
+  if (HasUnknownFields(descriptor_->file())) {
+    printer->Print("if (!unknown_fields().empty()) {\n");
+    printer->Indent();
+    printer->Print(
+      "total_size +=\n"
+      "  ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+      "    unknown_fields());\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
 
   // We update _cached_size_ even though this is a const method.  In theory,
   // this is not thread-compatible, because concurrent writes have undefined

+ 4 - 5
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -69,6 +69,10 @@ class MessageGenerator {
   // definitions because those classes use the enums definitions).
   void GenerateEnumDefinitions(io::Printer* printer);
 
+  // Generate specializations of GetEnumDescriptor<MyEnum>().
+  // Precondition: in ::google::protobuf namespace.
+  void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
+
   // Generate definitions for this class and all its nested types.
   void GenerateClassDefinition(io::Printer* printer);
 
@@ -125,11 +129,6 @@ class MessageGenerator {
   // Generate the shared destructor code.
   void GenerateSharedDestructorCode(io::Printer* printer);
 
-  // Generate the member initializer list for the constructors. The member
-  // initializer list is shared between the default constructor and the copy
-  // constructor.
-  void GenerateInitializerList(io::Printer* printer);
-
   // Generate standard Message methods.
   void GenerateClear(io::Printer* printer);
   void GenerateMergeFromCodedStream(io::Printer* printer);

+ 29 - 38
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -35,7 +35,6 @@
 #include <google/protobuf/compiler/cpp/cpp_message_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format_inl.h>
 #include <google/protobuf/stubs/strutil.h>
 
 namespace google {
@@ -43,22 +42,12 @@ namespace protobuf {
 namespace compiler {
 namespace cpp {
 
-using internal::WireFormat;
-
 namespace {
 
-// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
-//   repeat code between this and the other field types.
 void SetMessageVariables(const FieldDescriptor* descriptor,
                          map<string, string>* variables) {
-  (*variables)["name"] = FieldName(descriptor);
+  SetCommonFieldVariables(descriptor, variables);
   (*variables)["type"] = ClassName(descriptor->message_type(), true);
-  (*variables)["index"] = SimpleItoa(descriptor->index());
-  (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
-  (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
-  (*variables)["tag_size"] = SimpleItoa(
-    WireFormat::TagSize(descriptor->number(), descriptor->type()));
 }
 
 }  // namespace
@@ -81,8 +70,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void MessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const $type$& $name$() const;\n"
-    "inline $type$* mutable_$name$();\n");
+    "inline const $type$& $name$() const$deprecation$;\n"
+    "inline $type$* mutable_$name$()$deprecation$;\n");
 }
 
 void MessageFieldGenerator::
@@ -124,35 +113,35 @@ void MessageFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
       "     input, mutable_$name$()));\n");
   } else {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
-        "$number$, input, mutable_$name$()));\n");
+      "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+      "      $number$, input, mutable_$name$()));\n");
   }
 }
 
 void MessageFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
-    "::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
-      "$number$, this->$name$(), output);\n");
+    "::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n"
+    "  $number$, this->$name$(), output);\n");
 }
 
 void MessageFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
-    "target = ::google::protobuf::internal::WireFormat::"
-      "Write$declared_type$NoVirtualToArray("
-      "$number$, this->$name$(), target);\n");
+    "target = ::google::protobuf::internal::WireFormatLite::\n"
+    "  Write$declared_type$NoVirtualToArray(\n"
+    "    $number$, this->$name$(), target);\n");
 }
 
 void MessageFieldGenerator::
 GenerateByteSize(io::Printer* printer) const {
   printer->Print(variables_,
     "total_size += $tag_size$ +\n"
-    "  ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
+    "  ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
     "    this->$name$());\n");
 }
 
@@ -175,11 +164,13 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedMessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const;\n"
-    "inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$();\n"
-    "inline const $type$& $name$(int index) const;\n"
-    "inline $type$* mutable_$name$(int index);\n"
-    "inline $type$* add_$name$();\n");
+    "inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const"
+                 "$deprecation$;\n"
+    "inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$()"
+                 "$deprecation$;\n"
+    "inline const $type$& $name$(int index) const$deprecation$;\n"
+    "inline $type$* mutable_$name$(int index)$deprecation$;\n"
+    "inline $type$* add_$name$()$deprecation$;\n");
 }
 
 void RepeatedMessageFieldGenerator::
@@ -228,12 +219,12 @@ void RepeatedMessageFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
-      "     input, add_$name$()));\n");
+      "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+      "      input, add_$name$()));\n");
   } else {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
-        "$number$, input, add_$name$()));\n");
+      "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+      "      $number$, input, add_$name$()));\n");
   }
 }
 
@@ -241,8 +232,8 @@ void RepeatedMessageFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
     "for (int i = 0; i < this->$name$_size(); i++) {\n"
-    "  ::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
-        "$number$, this->$name$(i), output);\n"
+    "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n"
+    "    $number$, this->$name$(i), output);\n"
     "}\n");
 }
 
@@ -250,9 +241,9 @@ void RepeatedMessageFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
     "for (int i = 0; i < this->$name$_size(); i++) {\n"
-    "  target = ::google::protobuf::internal::WireFormat::"
-        "Write$declared_type$NoVirtualToArray("
-        "$number$, this->$name$(i), target);\n"
+    "  target = ::google::protobuf::internal::WireFormatLite::\n"
+    "    Write$declared_type$NoVirtualToArray(\n"
+    "      $number$, this->$name$(i), target);\n"
     "}\n");
 }
 
@@ -262,7 +253,7 @@ GenerateByteSize(io::Printer* printer) const {
     "total_size += $tag_size$ * this->$name$_size();\n"
     "for (int i = 0; i < this->$name$_size(); i++) {\n"
     "  total_size +=\n"
-    "    ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
+    "    ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
     "      this->$name$(i));\n"
     "}\n");
 }

+ 50 - 61
src/google/protobuf/compiler/cpp/cpp_primitive_field.cc

@@ -35,7 +35,7 @@
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
 namespace google {
@@ -43,7 +43,7 @@ namespace protobuf {
 namespace compiler {
 namespace cpp {
 
-using internal::WireFormat;
+using internal::WireFormatLite;
 
 namespace {
 
@@ -57,14 +57,14 @@ int FixedSize(FieldDescriptor::Type type) {
     case FieldDescriptor::TYPE_UINT64  : return -1;
     case FieldDescriptor::TYPE_SINT32  : return -1;
     case FieldDescriptor::TYPE_SINT64  : return -1;
-    case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size;
-    case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
-    case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
-    case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
-    case FieldDescriptor::TYPE_FLOAT   : return WireFormat::kFloatSize;
-    case FieldDescriptor::TYPE_DOUBLE  : return WireFormat::kDoubleSize;
-
-    case FieldDescriptor::TYPE_BOOL    : return WireFormat::kBoolSize;
+    case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT   : return WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE  : return WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL    : return WireFormatLite::kBoolSize;
     case FieldDescriptor::TYPE_ENUM    : return -1;
 
     case FieldDescriptor::TYPE_STRING  : return -1;
@@ -79,20 +79,11 @@ int FixedSize(FieldDescriptor::Type type) {
   return -1;
 }
 
-// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
-//   repeat code between this and the other field types.
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
                            map<string, string>* variables) {
-  (*variables)["name"] = FieldName(descriptor);
+  SetCommonFieldVariables(descriptor, variables);
   (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
   (*variables)["default"] = DefaultValue(descriptor);
-  (*variables)["index"] = SimpleItoa(descriptor->index());
-  (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
-  (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
-  (*variables)["tag_size"] = SimpleItoa(
-    WireFormat::TagSize(descriptor->number(), descriptor->type()));
-
   int fixed_size = FixedSize(descriptor->type());
   if (fixed_size != -1) {
     (*variables)["fixed_size"] = SimpleItoa(fixed_size);
@@ -119,8 +110,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void PrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$() const;\n"
-    "inline void set_$name$($type$ value);\n");
+    "inline $type$ $name$() const$deprecation$;\n"
+    "inline void set_$name$($type$ value)$deprecation$;\n");
 }
 
 void PrimitiveFieldGenerator::
@@ -158,7 +149,7 @@ GenerateConstructorCode(io::Printer* printer) const {
 void PrimitiveFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   printer->Print(variables_,
-    "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
+    "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
     "      input, &$name$_));\n"
     "_set_bit($index$);\n");
 }
@@ -166,14 +157,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
 void PrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
-    "::google::protobuf::internal::WireFormat::Write$declared_type$("
+    "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
       "$number$, this->$name$(), output);\n");
 }
 
 void PrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
-    "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray("
+    "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
       "$number$, this->$name$(), target);\n");
 }
 
@@ -183,7 +174,7 @@ GenerateByteSize(io::Printer* printer) const {
   if (fixed_size == -1) {
     printer->Print(variables_,
       "total_size += $tag_size$ +\n"
-      "  ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+      "  ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
       "    this->$name$());\n");
   } else {
     printer->Print(variables_,
@@ -205,8 +196,7 @@ void RepeatedPrimitiveFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
-  if (descriptor_->options().packed() &&
-      descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -215,11 +205,12 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedPrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const;\n"
-    "inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$();\n"
-    "inline $type$ $name$(int index) const;\n"
-    "inline void set_$name$(int index, $type$ value);\n"
-    "inline void add_$name$($type$ value);\n");
+    "inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const\n"
+    "    $deprecation$;\n"
+    "inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$()$deprecation$;\n"
+    "inline $type$ $name$(int index) const$deprecation$;\n"
+    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
+    "inline void add_$name$($type$ value)$deprecation$;\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
@@ -272,12 +263,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
     printer->Print(variables_,
       "::google::protobuf::uint32 length;\n"
       "DO_(input->ReadVarint32(&length));\n"
-      "::google::protobuf::io::CodedInputStream::Limit limit = "
-          "input->PushLimit(length);\n"
+      "::google::protobuf::io::CodedInputStream::Limit limit =\n"
+      "    input->PushLimit(length);\n"
       "while (input->BytesUntilLimit() > 0) {\n"
       "  $type$ value;\n"
-      "  DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
-        "input, &value));\n"
+      "  DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+      "        input, &value));\n"
       "  add_$name$(value);\n"
       "}\n"
       "input->PopLimit(limit);\n");
@@ -286,8 +277,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
   } else {
     printer->Print(variables_,
       "$type$ value;\n"
-      "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
-        "input, &value));\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+      "      input, &value));\n"
       "add_$name$(value);\n");
   }
 }
@@ -298,9 +289,9 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
-      "  ::google::protobuf::internal::WireFormat::WriteTag("
+      "  ::google::protobuf::internal::WireFormatLite::WriteTag("
           "$number$, "
-          "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
+          "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
           "output);\n"
       "  output->WriteVarint32(_$name$_cached_byte_size_);\n"
       "}\n");
@@ -309,12 +300,12 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::Write$declared_type$NoTag("
-          "this->$name$(i), output);\n");
+      "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
+      "    this->$name$(i), output);\n");
   } else {
     printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::Write$declared_type$("
-          "$number$, this->$name$(i), output);\n");
+      "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
+      "    $number$, this->$name$(i), output);\n");
   }
   printer->Print("}\n");
 }
@@ -325,26 +316,24 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
-      "  target = ::google::protobuf::internal::WireFormat::WriteTagToArray("
-          "$number$, "
-          "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
-          "target);\n"
-      "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
-          "_$name$_cached_byte_size_, target);\n"
+      "  target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
+      "    $number$,\n"
+      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
+      "    target);\n"
+      "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
+      "    _$name$_cached_byte_size_, target);\n"
       "}\n");
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
-      "  target = ::google::protobuf::internal::WireFormat::"
-          "Write$declared_type$NoTagToArray("
-          "this->$name$(i), target);\n");
+      "  target = ::google::protobuf::internal::WireFormatLite::\n"
+      "    Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
   } else {
     printer->Print(variables_,
-      "  target = ::google::protobuf::internal::WireFormat::"
-          "Write$declared_type$ToArray("
-          "$number$, this->$name$(i), target);\n");
+      "  target = ::google::protobuf::internal::WireFormatLite::\n"
+      "    Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
   }
   printer->Print("}\n");
 }
@@ -359,8 +348,8 @@ GenerateByteSize(io::Printer* printer) const {
   if (fixed_size == -1) {
     printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n"
-      "  data_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
-      "    this->$name$(i));\n"
+      "  data_size += ::google::protobuf::internal::WireFormatLite::\n"
+      "    $declared_type$Size(this->$name$(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
@@ -370,8 +359,8 @@ GenerateByteSize(io::Printer* printer) const {
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
-      "  total_size += $tag_size$ + "
-        "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
+      "  total_size += $tag_size$ +\n"
+      "    ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
       "}\n"
       "_$name$_cached_byte_size_ = data_size;\n"
       "total_size += data_size;\n");

+ 1 - 1
src/google/protobuf/compiler/cpp/cpp_service.cc

@@ -249,7 +249,7 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
     sub_vars["input_type"] = ClassName(method->input_type(), true);
     sub_vars["output_type"] = ClassName(method->output_type(), true);
 
-    // Note:  ::google::protobuf::down_cast does not work here because it only works on pointers,
+    // Note:  down_cast does not work here because it only works on pointers,
     //   not references.
     printer->Print(sub_vars,
       "    case $index$:\n"

+ 84 - 45
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -35,7 +35,6 @@
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format_inl.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
 
@@ -44,23 +43,13 @@ namespace protobuf {
 namespace compiler {
 namespace cpp {
 
-using internal::WireFormat;
-
 namespace {
 
-// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
-//   repeat code between this and the other field types.
 void SetStringVariables(const FieldDescriptor* descriptor,
                         map<string, string>* variables) {
-  (*variables)["name"] = FieldName(descriptor);
+  SetCommonFieldVariables(descriptor, variables);
   (*variables)["default"] =
     "\"" + CEscape(descriptor->default_value_string()) + "\"";
-  (*variables)["index"] = SimpleItoa(descriptor->index());
-  (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
-  (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
-  (*variables)["tag_size"] = SimpleItoa(
-    WireFormat::TagSize(descriptor->number(), descriptor->type()));
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
 }
@@ -111,11 +100,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   }
 
   printer->Print(variables_,
-    "inline const ::std::string& $name$() const;\n"
-    "inline void set_$name$(const ::std::string& value);\n"
-    "inline void set_$name$(const char* value);\n"
-    "inline void set_$name$(const $pointer_type$* value, size_t size);\n"
-    "inline ::std::string* mutable_$name$();\n");
+    "inline const ::std::string& $name$() const$deprecation$;\n"
+    "inline void set_$name$(const ::std::string& value)$deprecation$;\n"
+    "inline void set_$name$(const char* value)$deprecation$;\n"
+    "inline void set_$name$(const $pointer_type$* value, size_t size)"
+                 "$deprecation$;\n"
+    "inline ::std::string* mutable_$name$()$deprecation$;\n");
 
   if (descriptor_->options().has_ctype()) {
     printer->Outdent();
@@ -221,29 +211,52 @@ GenerateDestructorCode(io::Printer* printer) const {
 void StringFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   printer->Print(variables_,
-    "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
-      "input, mutable_$name$()));\n");
+    "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+    "      input, this->mutable_$name$()));\n");
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  this->$name$().data(), this->$name$().length(),\n"
+      "  ::google::protobuf::internal::WireFormat::PARSE);\n");
+  }
 }
 
 void StringFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  this->$name$().data(), this->$name$().length(),\n"
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+  }
   printer->Print(variables_,
-    "::google::protobuf::internal::WireFormat::Write$declared_type$("
-      "$number$, this->$name$(), output);\n");
+    "::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
+    "  $number$, this->$name$(), output);\n");
 }
 
 void StringFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  this->$name$().data(), this->$name$().length(),\n"
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+  }
   printer->Print(variables_,
-    "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray("
-      "$number$, this->$name$(), target);\n");
+    "target =\n"
+    "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n"
+    "    $number$, this->$name$(), target);\n");
 }
 
 void StringFieldGenerator::
 GenerateByteSize(io::Printer* printer) const {
   printer->Print(variables_,
     "total_size += $tag_size$ +\n"
-    "  ::google::protobuf::internal::WireFormat::$declared_type$Size(this->$name$());\n");
+    "  ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
+    "    this->$name$());\n");
 }
 
 // ===================================================================
@@ -274,18 +287,22 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   }
 
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const;\n"
-    "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$();\n"
-    "inline const ::std::string& $name$(int index) const;\n"
-    "inline ::std::string* mutable_$name$(int index);\n"
-    "inline void set_$name$(int index, const ::std::string& value);\n"
-    "inline void set_$name$(int index, const char* value);\n"
+    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
+                 "$deprecation$;\n"
+    "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+                 "$deprecation$;\n"
+    "inline const ::std::string& $name$(int index) const$deprecation$;\n"
+    "inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
+    "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
+    "inline void set_$name$(int index, const char* value)$deprecation$;\n"
     "inline "
-    "void set_$name$(int index, const $pointer_type$* value, size_t size);\n"
-    "inline ::std::string* add_$name$();\n"
-    "inline void add_$name$(const ::std::string& value);\n"
-    "inline void add_$name$(const char* value);\n"
-    "inline void add_$name$(const $pointer_type$* value, size_t size);\n");
+    "void set_$name$(int index, const $pointer_type$* value, size_t size)"
+                 "$deprecation$;\n"
+    "inline ::std::string* add_$name$()$deprecation$;\n"
+    "inline void add_$name$(const ::std::string& value)$deprecation$;\n"
+    "inline void add_$name$(const char* value)$deprecation$;\n"
+    "inline void add_$name$(const $pointer_type$* value, size_t size)"
+                 "$deprecation$;\n");
 
   if (descriptor_->options().has_ctype()) {
     printer->Outdent();
@@ -361,26 +378,48 @@ GenerateConstructorCode(io::Printer* printer) const {
 void RepeatedStringFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   printer->Print(variables_,
-    "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
-    "     input, add_$name$()));\n");
+    "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+    "      input, this->add_$name$()));\n");
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  this->$name$(0).data(), this->$name$(0).length(),\n"
+      "  ::google::protobuf::internal::WireFormat::PARSE);\n");
+  }
 }
 
 void RepeatedStringFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
-    "for (int i = 0; i < this->$name$_size(); i++) {\n"
-    "  ::google::protobuf::internal::WireFormat::Write$declared_type$("
-        "$number$, this->$name$(i), output);\n"
+    "for (int i = 0; i < this->$name$_size(); i++) {\n");
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  this->$name$(i).data(), this->$name$(i).length(),\n"
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+  }
+  printer->Print(variables_,
+    "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
+    "    $number$, this->$name$(i), output);\n"
     "}\n");
 }
 
 void RepeatedStringFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
-    "for (int i = 0; i < this->$name$_size(); i++) {\n"
-    "  target = ::google::protobuf::internal::WireFormat::"
-        "Write$declared_type$ToArray("
-        "$number$, this->$name$(i), target);\n"
+    "for (int i = 0; i < this->$name$_size(); i++) {\n");
+  if (HasUtf8Verification(descriptor_->file()) &&
+      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    printer->Print(variables_,
+      "  ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "    this->$name$(i).data(), this->$name$(i).length(),\n"
+      "    ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+  }
+  printer->Print(variables_,
+    "  target = ::google::protobuf::internal::WireFormatLite::\n"
+    "    Write$declared_type$ToArray($number$, this->$name$(i), target);\n"
     "}\n");
 }
 
@@ -389,7 +428,7 @@ GenerateByteSize(io::Printer* printer) const {
   printer->Print(variables_,
     "total_size += $tag_size$ * this->$name$_size();\n"
     "for (int i = 0; i < this->$name$_size(); i++) {\n"
-    "  total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+    "  total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
     "    this->$name$(i));\n"
     "}\n");
 }

+ 50 - 14
src/google/protobuf/compiler/cpp/cpp_unittest.cc

@@ -50,11 +50,9 @@
 #include <google/protobuf/unittest_optimize_for.pb.h>
 #include <google/protobuf/unittest_embed_optimize_for.pb.h>
 #include <google/protobuf/test_util.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
@@ -75,18 +73,6 @@ namespace cpp {
 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
 namespace cpp_unittest {
 
-TEST(ExtremeDefaultValues, FloatingPoint) {
-  const unittest::TestExtremeDefaultValues& extreme_default =
-      unittest::TestExtremeDefaultValues::default_instance();
-
-  EXPECT_EQ(0.0f, extreme_default.zero_float());
-  EXPECT_EQ(1.0f, extreme_default.one_float());
-  EXPECT_EQ(1.5f, extreme_default.small_float());
-  EXPECT_EQ(-1.0f, extreme_default.negative_one_float());
-  EXPECT_EQ(-1.5f, extreme_default.negative_float());
-  EXPECT_EQ(2.0e8f, extreme_default.large_float());
-  EXPECT_EQ(-8e-28f, extreme_default.small_negative_float());
-}
 
 class MockErrorCollector : public MultiFileErrorCollector {
  public:
@@ -157,6 +143,19 @@ TEST(GeneratedMessageTest, Defaults) {
             &message.optional_import_message());
 }
 
+TEST(GeneratedMessageTest, FloatingPointDefaults) {
+  const unittest::TestExtremeDefaultValues& extreme_default =
+      unittest::TestExtremeDefaultValues::default_instance();
+
+  EXPECT_EQ(0.0f, extreme_default.zero_float());
+  EXPECT_EQ(1.0f, extreme_default.one_float());
+  EXPECT_EQ(1.5f, extreme_default.small_float());
+  EXPECT_EQ(-1.0f, extreme_default.negative_one_float());
+  EXPECT_EQ(-1.5f, extreme_default.negative_float());
+  EXPECT_EQ(2.0e8f, extreme_default.large_float());
+  EXPECT_EQ(-8e-28f, extreme_default.small_negative_float());
+}
+
 TEST(GeneratedMessageTest, Accessors) {
   // Set every field to a unique value then go back and check all those
   // values.
@@ -710,6 +709,32 @@ TEST(GeneratedMessageTest, TestSpaceUsed) {
 
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
 
+TEST(GeneratedMessageTest, FieldConstantValues) {
+  unittest::TestRequired message;
+  EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1);
+  EXPECT_EQ(unittest::TestAllTypes::kOptionalInt32FieldNumber, 1);
+  EXPECT_EQ(unittest::TestAllTypes::kOptionalgroupFieldNumber, 16);
+  EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedMessageFieldNumber, 18);
+  EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedEnumFieldNumber, 21);
+  EXPECT_EQ(unittest::TestAllTypes::kRepeatedInt32FieldNumber, 31);
+  EXPECT_EQ(unittest::TestAllTypes::kRepeatedgroupFieldNumber, 46);
+  EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48);
+  EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51);
+}
+
+TEST(GeneratedMessageTest, ExtensionConstantValues) {
+  EXPECT_EQ(unittest::TestRequired::kSingleFieldNumber, 1000);
+  EXPECT_EQ(unittest::TestRequired::kMultiFieldNumber, 1001);
+  EXPECT_EQ(unittest::kOptionalInt32ExtensionFieldNumber, 1);
+  EXPECT_EQ(unittest::kOptionalgroupExtensionFieldNumber, 16);
+  EXPECT_EQ(unittest::kOptionalNestedMessageExtensionFieldNumber, 18);
+  EXPECT_EQ(unittest::kOptionalNestedEnumExtensionFieldNumber, 21);
+  EXPECT_EQ(unittest::kRepeatedInt32ExtensionFieldNumber, 31);
+  EXPECT_EQ(unittest::kRepeatedgroupExtensionFieldNumber, 46);
+  EXPECT_EQ(unittest::kRepeatedNestedMessageExtensionFieldNumber, 48);
+  EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
+}
+
 // ===================================================================
 
 TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
@@ -803,6 +828,17 @@ TEST(GeneratedEnumTest, Parse) {
   EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value));
 }
 
+TEST(GeneratedEnumTest, GetEnumDescriptor) {
+  EXPECT_EQ(unittest::TestAllTypes::NestedEnum_descriptor(),
+            GetEnumDescriptor<unittest::TestAllTypes::NestedEnum>());
+  EXPECT_EQ(unittest::ForeignEnum_descriptor(),
+            GetEnumDescriptor<unittest::ForeignEnum>());
+  EXPECT_EQ(unittest::TestEnumWithDupValue_descriptor(),
+            GetEnumDescriptor<unittest::TestEnumWithDupValue>());
+  EXPECT_EQ(unittest::TestSparseEnum_descriptor(),
+            GetEnumDescriptor<unittest::TestSparseEnum>());
+}
+
 #endif  // PROTOBUF_TEST_NO_DESCRIPTORS
 
 // ===================================================================

+ 84 - 64
src/google/protobuf/compiler/java/java_enum.cc

@@ -67,14 +67,17 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
 EnumGenerator::~EnumGenerator() {}
 
 void EnumGenerator::Generate(io::Printer* printer) {
-  bool is_own_file =
-    descriptor_->containing_type() == NULL &&
-    descriptor_->file()->options().java_multiple_files();
-  printer->Print(
-    "public $static$ enum $classname$\n"
-    "    implements com.google.protobuf.ProtocolMessageEnum {\n",
-    "static", is_own_file ? "" : "static",
-    "classname", descriptor_->name());
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "public enum $classname$\n"
+      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "public enum $classname$\n"
+      "    implements com.google.protobuf.Internal.EnumLite {\n",
+      "classname", descriptor_->name());
+  }
   printer->Indent();
 
   for (int i = 0; i < canonical_values_.size(); i++) {
@@ -126,63 +129,78 @@ void EnumGenerator::Generate(io::Printer* printer) {
     "    default: return null;\n"
     "  }\n"
     "}\n"
-    "\n");
+    "\n"
+    "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
+    "    internalGetValueMap() {\n"
+    "  return internalValueMap;\n"
+    "}\n"
+    "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
+    "    internalValueMap =\n"
+    "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
+    "        public $classname$ findValueByNumber(int number) {\n"
+    "          return $classname$.valueOf(number)\n;"
+    "        }\n"
+    "      };\n"
+    "\n",
+    "classname", descriptor_->name());
 
   // -----------------------------------------------------------------
   // Reflection
 
-  printer->Print(
-    "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
-    "    getValueDescriptor() {\n"
-    "  return getDescriptor().getValues().get(index);\n"
-    "}\n"
-    "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
-    "    getDescriptorForType() {\n"
-    "  return getDescriptor();\n"
-    "}\n"
-    "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
-    "    getDescriptor() {\n");
-
-  // TODO(kenton):  Cache statically?  Note that we can't access descriptors
-  //   at module init time because it wouldn't work with descriptor.proto, but
-  //   we can cache the value the first time getDescriptor() is called.
-  if (descriptor_->containing_type() == NULL) {
+  if (HasDescriptorMethods(descriptor_)) {
     printer->Print(
-      "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
-      "file", ClassName(descriptor_->file()),
-      "index", SimpleItoa(descriptor_->index()));
-  } else {
-    printer->Print(
-      "  return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
-      "parent", ClassName(descriptor_->containing_type()),
-      "index", SimpleItoa(descriptor_->index()));
-  }
+      "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
+      "    getValueDescriptor() {\n"
+      "  return getDescriptor().getValues().get(index);\n"
+      "}\n"
+      "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
+      "    getDescriptorForType() {\n"
+      "  return getDescriptor();\n"
+      "}\n"
+      "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
+      "    getDescriptor() {\n");
+
+    // TODO(kenton):  Cache statically?  Note that we can't access descriptors
+    //   at module init time because it wouldn't work with descriptor.proto, but
+    //   we can cache the value the first time getDescriptor() is called.
+    if (descriptor_->containing_type() == NULL) {
+      printer->Print(
+        "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
+        "file", ClassName(descriptor_->file()),
+        "index", SimpleItoa(descriptor_->index()));
+    } else {
+      printer->Print(
+        "  return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
+        "parent", ClassName(descriptor_->containing_type()),
+        "index", SimpleItoa(descriptor_->index()));
+    }
 
-  printer->Print(
-    "}\n"
-    "\n"
-    "private static final $classname$[] VALUES = {\n"
-    "  ",
-    "classname", descriptor_->name());
+    printer->Print(
+      "}\n"
+      "\n"
+      "private static final $classname$[] VALUES = {\n"
+      "  ",
+      "classname", descriptor_->name());
+
+    for (int i = 0; i < descriptor_->value_count(); i++) {
+      printer->Print("$name$, ",
+        "name", descriptor_->value(i)->name());
+    }
 
-  for (int i = 0; i < descriptor_->value_count(); i++) {
-    printer->Print("$name$, ",
-      "name", descriptor_->value(i)->name());
+    printer->Print(
+      "\n"
+      "};\n"
+      "public static $classname$ valueOf(\n"
+      "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
+      "  if (desc.getType() != getDescriptor()) {\n"
+      "    throw new java.lang.IllegalArgumentException(\n"
+      "      \"EnumValueDescriptor is not for this type.\");\n"
+      "  }\n"
+      "  return VALUES[desc.getIndex()];\n"
+      "}\n",
+      "classname", descriptor_->name());
   }
 
-  printer->Print(
-    "\n"
-    "};\n"
-    "public static $classname$ valueOf(\n"
-    "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
-    "  if (desc.getType() != getDescriptor()) {\n"
-    "    throw new java.lang.IllegalArgumentException(\n"
-    "      \"EnumValueDescriptor is not for this type.\");\n"
-    "  }\n"
-    "  return VALUES[desc.getIndex()];\n"
-    "}\n",
-    "classname", descriptor_->name());
-
   // -----------------------------------------------------------------
 
   printer->Print(
@@ -194,14 +212,16 @@ void EnumGenerator::Generate(io::Printer* printer) {
     "}\n",
     "classname", descriptor_->name());
 
-  // Force the static initialization code for the file to run, since it may
-  // initialize static variables declared in this class.
-  printer->Print(
-    "\n"
-    "static {\n"
-    "  $file$.getDescriptor();\n"
-    "}\n",
-    "file", ClassName(descriptor_->file()));
+  if (HasDescriptorMethods(descriptor_)) {
+    // Force the static initialization code for the file to run, since it may
+    // initialize static variables declared in this class.
+    printer->Print(
+      "\n"
+      "static {\n"
+      "  $file$.getDescriptor();\n"
+      "}\n",
+      "file", ClassName(descriptor_->file()));
+  }
 
   printer->Outdent();
   printer->Print("}\n\n");

+ 26 - 17
src/google/protobuf/compiler/java/java_enum_field.cc

@@ -39,7 +39,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
 namespace google {
@@ -53,18 +53,13 @@ namespace {
 //   repeat code between this and the other field types.
 void SetEnumVariables(const FieldDescriptor* descriptor,
                       map<string, string>* variables) {
-  const EnumValueDescriptor* default_value;
-  default_value = descriptor->default_value_enum();
-
-  string type = ClassName(descriptor->enum_type());
-
   (*variables)["name"] =
     UnderscoresToCamelCase(descriptor);
   (*variables)["capitalized_name"] =
     UnderscoresToCapitalizedCamelCase(descriptor);
   (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["type"] = type;
-  (*variables)["default"] = type + "." + default_value->name();
+  (*variables)["type"] = ClassName(descriptor->enum_type());
+  (*variables)["default"] = DefaultValue(descriptor);
   (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
@@ -132,10 +127,17 @@ void EnumFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   printer->Print(variables_,
     "int rawValue = input.readEnum();\n"
-    "$type$ value = $type$.valueOf(rawValue);\n"
-    "if (value == null) {\n"
-    "  unknownFields.mergeVarintField($number$, rawValue);\n"
-    "} else {\n"
+    "$type$ value = $type$.valueOf(rawValue);\n");
+  if (HasUnknownFields(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "if (value == null) {\n"
+      "  unknownFields.mergeVarintField($number$, rawValue);\n"
+      "} else {\n");
+  } else {
+    printer->Print(variables_,
+      "if (value != null) {\n");
+  }
+  printer->Print(variables_,
     "  set$capitalized_name$(value);\n"
     "}\n");
 }
@@ -185,7 +187,7 @@ GenerateMembers(io::Printer* printer) const {
     "}\n");
 
   if (descriptor_->options().packed() &&
-      descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+      HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
   }
@@ -272,10 +274,17 @@ GenerateParsingCode(io::Printer* printer) const {
   // Read and store the enum
   printer->Print(variables_,
     "int rawValue = input.readEnum();\n"
-    "$type$ value = $type$.valueOf(rawValue);\n"
-    "if (value == null) {\n"
-    "  unknownFields.mergeVarintField($number$, rawValue);\n"
-    "} else {\n"
+    "$type$ value = $type$.valueOf(rawValue);\n");
+  if (HasUnknownFields(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "if (value == null) {\n"
+      "  unknownFields.mergeVarintField($number$, rawValue);\n"
+      "} else {\n");
+  } else {
+    printer->Print(variables_,
+      "if (value != null) {\n");
+  }
+  printer->Print(variables_,
     "  add$capitalized_name$(value);\n"
     "}\n");
 

+ 85 - 14
src/google/protobuf/compiler/java/java_extension.cc

@@ -42,6 +42,39 @@ namespace protobuf {
 namespace compiler {
 namespace java {
 
+namespace {
+
+const char* TypeName(FieldDescriptor::Type field_type) {
+  switch (field_type) {
+    case FieldDescriptor::TYPE_INT32   : return "INT32";
+    case FieldDescriptor::TYPE_UINT32  : return "UINT32";
+    case FieldDescriptor::TYPE_SINT32  : return "SINT32";
+    case FieldDescriptor::TYPE_FIXED32 : return "FIXED32";
+    case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32";
+    case FieldDescriptor::TYPE_INT64   : return "INT64";
+    case FieldDescriptor::TYPE_UINT64  : return "UINT64";
+    case FieldDescriptor::TYPE_SINT64  : return "SINT64";
+    case FieldDescriptor::TYPE_FIXED64 : return "FIXED64";
+    case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64";
+    case FieldDescriptor::TYPE_FLOAT   : return "FLOAT";
+    case FieldDescriptor::TYPE_DOUBLE  : return "DOUBLE";
+    case FieldDescriptor::TYPE_BOOL    : return "BOOL";
+    case FieldDescriptor::TYPE_STRING  : return "STRING";
+    case FieldDescriptor::TYPE_BYTES   : return "BYTES";
+    case FieldDescriptor::TYPE_ENUM    : return "ENUM";
+    case FieldDescriptor::TYPE_GROUP   : return "GROUP";
+    case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE";
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+}
+
 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor)
   : descriptor_(descriptor) {
   if (descriptor_->extension_scope() != NULL) {
@@ -59,6 +92,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
   vars["containing_type"] = ClassName(descriptor_->containing_type());
   vars["number"] = SimpleItoa(descriptor_->number());
   vars["constant_name"] = FieldConstantName(descriptor_);
+  vars["lite"] = HasDescriptorMethods(descriptor_->file()) ? "" : "Lite";
 
   JavaType java_type = GetJavaType(descriptor_);
   string singular_type;
@@ -79,13 +113,13 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
   if (descriptor_->is_repeated()) {
     printer->Print(vars,
       "public static\n"
-      "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "  com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
       "    $containing_type$,\n"
       "    java.util.List<$type$>> $name$;\n");
   } else {
     printer->Print(vars,
       "public static\n"
-      "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "  com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
       "    $containing_type$,\n"
       "    $type$> $name$;\n");
   }
@@ -96,34 +130,71 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) {
   vars["name"] = UnderscoresToCamelCase(descriptor_);
   vars["scope"] = scope_;
   vars["index"] = SimpleItoa(descriptor_->index());
+  vars["extendee"] = ClassName(descriptor_->containing_type());
+  vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_);
+  vars["number"] = SimpleItoa(descriptor_->number());
+  vars["type_constant"] = TypeName(descriptor_->type());
+  vars["packed"] = descriptor_->options().packed() ? "true" : "false";
+  vars["enum_map"] = "null";
+  vars["prototype"] = "null";
 
   JavaType java_type = GetJavaType(descriptor_);
   string singular_type;
   switch (java_type) {
     case JAVATYPE_MESSAGE:
       vars["type"] = ClassName(descriptor_->message_type());
+      vars["prototype"] = ClassName(descriptor_->message_type()) +
+                          ".getDefaultInstance()";
       break;
     case JAVATYPE_ENUM:
       vars["type"] = ClassName(descriptor_->enum_type());
+      vars["enum_map"] = ClassName(descriptor_->enum_type()) +
+                         ".internalGetValueMap()";
       break;
     default:
       vars["type"] = BoxedPrimitiveTypeName(java_type);
       break;
   }
 
-  if (descriptor_->is_repeated()) {
-    printer->Print(vars,
-      "$scope$.$name$ =\n"
-      "  com.google.protobuf.GeneratedMessage\n"
-      "    .newRepeatedGeneratedExtension(\n"
-      "      $scope$.getDescriptor().getExtensions().get($index$),\n"
-      "      $type$.class);\n");
+  if (HasDescriptorMethods(descriptor_->file())) {
+    if (descriptor_->is_repeated()) {
+      printer->Print(vars,
+        "$scope$.$name$ =\n"
+        "  com.google.protobuf.GeneratedMessage\n"
+        "    .newRepeatedGeneratedExtension(\n"
+        "      $scope$.getDescriptor().getExtensions().get($index$),\n"
+        "      $type$.class);\n");
+    } else {
+      printer->Print(vars,
+        "$scope$.$name$ =\n"
+        "  com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n"
+        "    $scope$.getDescriptor().getExtensions().get($index$),\n"
+        "    $type$.class);\n");
+    }
   } else {
-    printer->Print(vars,
-      "$scope$.$name$ =\n"
-      "  com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n"
-      "    $scope$.getDescriptor().getExtensions().get($index$),\n"
-      "    $type$.class);\n");
+    if (descriptor_->is_repeated()) {
+      printer->Print(vars,
+        "$scope$.$name$ =\n"
+        "  com.google.protobuf.GeneratedMessageLite\n"
+        "    .newRepeatedGeneratedExtension(\n"
+        "      $extendee$.getDefaultInstance(),\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+        "      $packed$);\n");
+    } else {
+      printer->Print(vars,
+        "$scope$.$name$ =\n"
+        "  com.google.protobuf.GeneratedMessageLite\n"
+        "    .newGeneratedExtension(\n"
+        "      $extendee$.getDefaultInstance(),\n"
+        "      $default$,\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
+    }
   }
 }
 

+ 38 - 5
src/google/protobuf/compiler/java/java_file.cc

@@ -151,7 +151,9 @@ void FileGenerator::Generate(io::Printer* printer) {
 
   printer->Print(
     "public static void registerAllExtensions(\n"
-    "    com.google.protobuf.ExtensionRegistry registry) {\n");
+    "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
+    "lite", HasDescriptorMethods(file_) ? "" : "Lite");
+
   printer->Indent();
 
   for (int i = 0; i < file_->extension_count(); i++) {
@@ -195,8 +197,42 @@ void FileGenerator::Generate(io::Printer* printer) {
 
   printer->Print("\n");
 
-  // -----------------------------------------------------------------
+  if (HasDescriptorMethods(file_)) {
+    GenerateEmbeddedDescriptor(printer);
+  } else {
+    printer->Print(
+      "static {\n");
+    printer->Indent();
 
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      // TODO(kenton):  Reuse MessageGenerator objects?
+      MessageGenerator(file_->message_type(i))
+        .GenerateStaticVariableInitializers(printer);
+    }
+
+    for (int i = 0; i < file_->extension_count(); i++) {
+      // TODO(kenton):  Reuse ExtensionGenerator objects?
+      ExtensionGenerator(file_->extension(i))
+        .GenerateInitializationCode(printer);
+    }
+
+    printer->Outdent();
+    printer->Print(
+      "}\n");
+  }
+
+  // Dummy function we can use to force the static initialization block to
+  // run.  Needed by inner classes.  Cannot be private due to
+  // java_multiple_files option.
+  printer->Print(
+    "\n"
+    "public static void internalForceInit() {}\n");
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
   // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
   // and embed it as a string literal, which is parsed and built into real
   // descriptors at initialization time.  We unfortunately have to put it in
@@ -310,9 +346,6 @@ void FileGenerator::Generate(io::Printer* printer) {
   printer->Outdent();
   printer->Print(
     "}\n");
-
-  printer->Outdent();
-  printer->Print("}\n");
 }
 
 template<typename GeneratorClass, typename DescriptorClass>

+ 2 - 0
src/google/protobuf/compiler/java/java_file.h

@@ -81,6 +81,8 @@ class FileGenerator {
   string java_package_;
   string classname_;
 
+  void GenerateEmbeddedDescriptor(io::Printer* printer);
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
 };
 

+ 1 - 27
src/google/protobuf/compiler/java/java_generator.cc

@@ -45,32 +45,6 @@ namespace protobuf {
 namespace compiler {
 namespace java {
 
-namespace {
-
-// Parses a set of comma-delimited name/value pairs, e.g.:
-//   "foo=bar,baz,qux=corge"
-// parses to the pairs:
-//   ("foo", "bar"), ("baz", ""), ("qux", "corge")
-void ParseOptions(const string& text, vector<pair<string, string> >* output) {
-  vector<string> parts;
-  SplitStringUsing(text, ",", &parts);
-
-  for (int i = 0; i < parts.size(); i++) {
-    string::size_type equals_pos = parts[i].find_first_of('=');
-    pair<string, string> value;
-    if (equals_pos == string::npos) {
-      value.first = parts[i];
-      value.second = "";
-    } else {
-      value.first = parts[i].substr(0, equals_pos);
-      value.second = parts[i].substr(equals_pos + 1);
-    }
-    output->push_back(value);
-  }
-}
-
-}  // namespace
-
 JavaGenerator::JavaGenerator() {}
 JavaGenerator::~JavaGenerator() {}
 
@@ -79,7 +53,7 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
                              OutputDirectory* output_directory,
                              string* error) const {
   vector<pair<string, string> > options;
-  ParseOptions(parameter, &options);
+  ParseGeneratorParameter(parameter, &options);
 
   // -----------------------------------------------------------------
   // parse generator options

+ 67 - 0
src/google/protobuf/compiler/java/java_helpers.cc

@@ -37,6 +37,7 @@
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
@@ -243,6 +244,72 @@ const char* BoxedPrimitiveTypeName(JavaType type) {
   return NULL;
 }
 
+bool AllAscii(const string& text) {
+  for (int i = 0; i < text.size(); i++) {
+    if ((text[i] & 0x80) != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+string DefaultValue(const FieldDescriptor* field) {
+  // Switch on cpp_type since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return SimpleItoa(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      // Need to print as a signed int since Java has no unsigned.
+      return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
+    case FieldDescriptor::CPPTYPE_INT64:
+      return SimpleItoa(field->default_value_int64()) + "L";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
+             "L";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return SimpleDtoa(field->default_value_double()) + "D";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return SimpleFtoa(field->default_value_float()) + "F";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->type() == FieldDescriptor::TYPE_BYTES) {
+        if (field->has_default_value()) {
+          // See comments in Internal.java for gory details.
+          return strings::Substitute(
+            "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
+            CEscape(field->default_value_string()));
+        } else {
+          return "com.google.protobuf.ByteString.EMPTY";
+        }
+      } else {
+        if (AllAscii(field->default_value_string())) {
+          // All chars are ASCII.  In this case CEscape() works fine.
+          return "\"" + CEscape(field->default_value_string()) + "\"";
+        } else {
+          // See comments in Internal.java for gory details.
+          return strings::Substitute(
+            "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
+            CEscape(field->default_value_string()));
+        }
+      }
+
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return ClassName(field->enum_type()) + "." +
+             field->default_value_enum()->name();
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return ClassName(field->message_type()) + ".getDefaultInstance()";
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf

+ 30 - 0
src/google/protobuf/compiler/java/java_helpers.h

@@ -36,6 +36,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
 
 #include <string>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
 
 namespace google {
@@ -115,6 +116,35 @@ inline JavaType GetJavaType(const FieldDescriptor* field) {
 // types.
 const char* BoxedPrimitiveTypeName(JavaType type);
 
+string DefaultValue(const FieldDescriptor* field);
+
+// Does this message class keep track of unknown fields?
+inline bool HasUnknownFields(const Descriptor* descriptor) {
+  return descriptor->file()->options().optimize_for() !=
+           FileOptions::LITE_RUNTIME;
+}
+
+// Does this message class have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+inline bool HasGeneratedMethods(const Descriptor* descriptor) {
+  return descriptor->file()->options().optimize_for() !=
+           FileOptions::CODE_SIZE;
+}
+
+// Does this message class have descriptor and reflection methods?
+inline bool HasDescriptorMethods(const Descriptor* descriptor) {
+  return descriptor->file()->options().optimize_for() !=
+           FileOptions::LITE_RUNTIME;
+}
+inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) {
+  return descriptor->file()->options().optimize_for() !=
+           FileOptions::LITE_RUNTIME;
+}
+inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
+  return descriptor->options().optimize_for() !=
+           FileOptions::LITE_RUNTIME;
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf

+ 300 - 178
src/google/protobuf/compiler/java/java_message.cc

@@ -41,7 +41,7 @@
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/descriptor.pb.h>
 
 namespace google {
@@ -50,6 +50,7 @@ namespace compiler {
 namespace java {
 
 using internal::WireFormat;
+using internal::WireFormatLite;
 
 namespace {
 
@@ -153,38 +154,41 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor)
 MessageGenerator::~MessageGenerator() {}
 
 void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
-  // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
-  // used in the construction of descriptors, we have a tricky bootstrapping
-  // problem.  To help control static initialization order, we make sure all
-  // descriptors and other static data that depends on them are members of
-  // the outermost class in the file.  This way, they will be initialized in
-  // a deterministic order.
-
-  map<string, string> vars;
-  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-  vars["index"] = SimpleItoa(descriptor_->index());
-  vars["classname"] = ClassName(descriptor_);
-  if (descriptor_->containing_type() != NULL) {
-    vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
-  }
-  if (descriptor_->file()->options().java_multiple_files()) {
-    // We can only make these package-private since the classes that use them
-    // are in separate files.
-    vars["private"] = "";
-  } else {
-    vars["private"] = "private ";
-  }
+  if (HasDescriptorMethods(descriptor_)) {
+    // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+    // used in the construction of descriptors, we have a tricky bootstrapping
+    // problem.  To help control static initialization order, we make sure all
+    // descriptors and other static data that depends on them are members of
+    // the outermost class in the file.  This way, they will be initialized in
+    // a deterministic order.
+
+    map<string, string> vars;
+    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+    vars["index"] = SimpleItoa(descriptor_->index());
+    vars["classname"] = ClassName(descriptor_);
+    if (descriptor_->containing_type() != NULL) {
+      vars["parent"] = UniqueFileScopeIdentifier(
+          descriptor_->containing_type());
+    }
+    if (descriptor_->file()->options().java_multiple_files()) {
+      // We can only make these package-private since the classes that use them
+      // are in separate files.
+      vars["private"] = "";
+    } else {
+      vars["private"] = "private ";
+    }
 
-  // The descriptor for this type.
-  printer->Print(vars,
-    "$private$static com.google.protobuf.Descriptors.Descriptor\n"
-    "  internal_$identifier$_descriptor;\n");
+    // The descriptor for this type.
+    printer->Print(vars,
+      "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+      "  internal_$identifier$_descriptor;\n");
 
-  // And the FieldAccessorTable.
-  printer->Print(vars,
-    "$private$static\n"
-    "  com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
-    "    internal_$identifier$_fieldAccessorTable;\n");
+    // And the FieldAccessorTable.
+    printer->Print(vars,
+      "$private$static\n"
+      "  com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+      "    internal_$identifier$_fieldAccessorTable;\n");
+  }
 
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -196,41 +200,44 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
 
 void MessageGenerator::GenerateStaticVariableInitializers(
     io::Printer* printer) {
-  map<string, string> vars;
-  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-  vars["index"] = SimpleItoa(descriptor_->index());
-  vars["classname"] = ClassName(descriptor_);
-  if (descriptor_->containing_type() != NULL) {
-    vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
-  }
+  if (HasDescriptorMethods(descriptor_)) {
+    map<string, string> vars;
+    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+    vars["index"] = SimpleItoa(descriptor_->index());
+    vars["classname"] = ClassName(descriptor_);
+    if (descriptor_->containing_type() != NULL) {
+      vars["parent"] = UniqueFileScopeIdentifier(
+          descriptor_->containing_type());
+    }
 
-  // The descriptor for this type.
-  if (descriptor_->containing_type() == NULL) {
-    printer->Print(vars,
-      "internal_$identifier$_descriptor =\n"
-      "  getDescriptor().getMessageTypes().get($index$);\n");
-  } else {
-    printer->Print(vars,
-      "internal_$identifier$_descriptor =\n"
-      "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
-  }
+    // The descriptor for this type.
+    if (descriptor_->containing_type() == NULL) {
+      printer->Print(vars,
+        "internal_$identifier$_descriptor =\n"
+        "  getDescriptor().getMessageTypes().get($index$);\n");
+    } else {
+      printer->Print(vars,
+        "internal_$identifier$_descriptor =\n"
+        "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
+    }
 
-  // And the FieldAccessorTable.
-  printer->Print(vars,
-    "internal_$identifier$_fieldAccessorTable = new\n"
-    "  com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
-    "    internal_$identifier$_descriptor,\n"
-    "    new java.lang.String[] { ");
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    printer->Print(
-      "\"$field_name$\", ",
-      "field_name",
-        UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
+    // And the FieldAccessorTable.
+    printer->Print(vars,
+      "internal_$identifier$_fieldAccessorTable = new\n"
+      "  com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
+      "    internal_$identifier$_descriptor,\n"
+      "    new java.lang.String[] { ");
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      printer->Print(
+        "\"$field_name$\", ",
+        "field_name",
+          UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
+    }
+    printer->Print("},\n"
+      "    $classname$.class,\n"
+      "    $classname$.Builder.class);\n",
+      "classname", ClassName(descriptor_));
   }
-  printer->Print("},\n"
-    "    $classname$.class,\n"
-    "    $classname$.Builder.class);\n",
-    "classname", ClassName(descriptor_));
 
   // Generate static member initializers for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -252,18 +259,35 @@ void MessageGenerator::Generate(io::Printer* printer) {
     descriptor_->file()->options().java_multiple_files();
 
   if (descriptor_->extension_range_count() > 0) {
-    printer->Print(
-      "public $static$ final class $classname$ extends\n"
-      "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-      "      $classname$> {\n",
-      "static", is_own_file ? "" : "static",
-      "classname", descriptor_->name());
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public $static$ final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+        "      $classname$> {\n",
+        "static", is_own_file ? "" : "static",
+        "classname", descriptor_->name());
+    } else {
+      printer->Print(
+        "public $static$ final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
+        "      $classname$> {\n",
+        "static", is_own_file ? "" : "static",
+        "classname", descriptor_->name());
+    }
   } else {
-    printer->Print(
-      "public $static$ final class $classname$ extends\n"
-      "    com.google.protobuf.GeneratedMessage {\n",
-      "static", is_own_file ? "" : "static",
-      "classname", descriptor_->name());
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public $static$ final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessage {\n",
+        "static", is_own_file ? "" : "static",
+        "classname", descriptor_->name());
+    } else {
+      printer->Print(
+        "public $static$ final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite {\n",
+        "static", is_own_file ? "" : "static",
+        "classname", descriptor_->name());
+    }
   }
   printer->Indent();
   printer->Print(
@@ -280,20 +304,23 @@ void MessageGenerator::Generate(io::Printer* printer) {
     "}\n"
     "\n",
     "classname", descriptor_->name());
-  printer->Print(
-    "public static final com.google.protobuf.Descriptors.Descriptor\n"
-    "    getDescriptor() {\n"
-    "  return $fileclass$.internal_$identifier$_descriptor;\n"
-    "}\n"
-    "\n"
-    "@Override\n"
-    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
-    "    internalGetFieldAccessorTable() {\n"
-    "  return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
-    "}\n"
-    "\n",
-    "fileclass", ClassName(descriptor_->file()),
-    "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
+      "  return $fileclass$.internal_$identifier$_descriptor;\n"
+      "}\n"
+      "\n"
+      "@Override\n"
+      "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+      "    internalGetFieldAccessorTable() {\n"
+      "  return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
+      "}\n"
+      "\n",
+      "fileclass", ClassName(descriptor_->file()),
+      "identifier", UniqueFileScopeIdentifier(descriptor_));
+  }
 
   // Nested types and extensions
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -318,7 +345,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
     printer->Print("\n");
   }
 
-  if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (HasGeneratedMethods(descriptor_)) {
     GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
   }
@@ -326,12 +353,23 @@ void MessageGenerator::Generate(io::Printer* printer) {
   GenerateParseFromMethods(printer);
   GenerateBuilder(printer);
 
-  // Force the static initialization code for the file to run, since it may
-  // initialize static variables declared in this class.
+  if (HasDescriptorMethods(descriptor_)) {
+    // Force the static initialization code for the file to run, since it may
+    // initialize static variables declared in this class.
+    printer->Print(
+      "\n"
+      "static {\n"
+      "  $file$.getDescriptor();\n"
+      "}\n",
+      "file", ClassName(descriptor_->file()));
+  }
+
+  // Force initialization of outer class.  Otherwise, nested extensions may
+  // not be initialized.
   printer->Print(
     "\n"
     "static {\n"
-    "  $file$.getDescriptor();\n"
+    "  $file$.internalForceInit();\n"
     "}\n",
     "file", ClassName(descriptor_->file()));
 
@@ -360,9 +398,18 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
   printer->Indent();
 
   if (descriptor_->extension_range_count() > 0) {
-    printer->Print(
-      "com.google.protobuf.GeneratedMessage.ExtendableMessage\n"
-      "  .ExtensionWriter extensionWriter = newExtensionWriter();\n");
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage\n"
+        "  .ExtensionWriter extensionWriter =\n"
+        "    newMessageSetExtensionWriter();\n",
+        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite");
+    } else {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage\n"
+        "  .ExtensionWriter extensionWriter = newExtensionWriter();\n",
+        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite");
+    }
   }
 
   // Merge the fields and the extension ranges, both sorted by field number.
@@ -380,12 +427,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
     }
   }
 
-  if (descriptor_->options().message_set_wire_format()) {
-    printer->Print(
-      "getUnknownFields().writeAsMessageSetTo(output);\n");
-  } else {
-    printer->Print(
-      "getUnknownFields().writeTo(output);\n");
+  if (HasUnknownFields(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "getUnknownFields().writeAsMessageSetTo(output);\n");
+    } else {
+      printer->Print(
+        "getUnknownFields().writeTo(output);\n");
+    }
   }
 
   printer->Outdent();
@@ -406,16 +455,23 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
   }
 
   if (descriptor_->extension_range_count() > 0) {
-    printer->Print(
-      "size += extensionsSerializedSize();\n");
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "size += extensionsSerializedSizeAsMessageSet();\n");
+    } else {
+      printer->Print(
+        "size += extensionsSerializedSize();\n");
+    }
   }
 
-  if (descriptor_->options().message_set_wire_format()) {
-    printer->Print(
-      "size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
-  } else {
-    printer->Print(
-      "size += getUnknownFields().getSerializedSize();\n");
+  if (HasUnknownFields(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
+    } else {
+      printer->Print(
+        "size += getUnknownFields().getSerializedSize();\n");
+    }
   }
 
   printer->Outdent();
@@ -439,7 +495,7 @@ GenerateParseFromMethods(io::Printer* printer) {
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.ByteString data,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
     "  return newBuilder().mergeFrom(data, extensionRegistry)\n"
     "           .buildParsed();\n"
@@ -450,7 +506,7 @@ GenerateParseFromMethods(io::Printer* printer) {
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    byte[] data,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
     "  return newBuilder().mergeFrom(data, extensionRegistry)\n"
     "           .buildParsed();\n"
@@ -461,7 +517,7 @@ GenerateParseFromMethods(io::Printer* printer) {
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
     "  return newBuilder().mergeFrom(input, extensionRegistry)\n"
     "           .buildParsed();\n"
@@ -472,7 +528,7 @@ GenerateParseFromMethods(io::Printer* printer) {
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
     "  return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n"
     "           .buildParsed();\n"
@@ -484,7 +540,7 @@ GenerateParseFromMethods(io::Printer* printer) {
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
     "  return newBuilder().mergeFrom(input, extensionRegistry)\n"
     "           .buildParsed();\n"
@@ -509,32 +565,57 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
 
 void MessageGenerator::GenerateBuilder(io::Printer* printer) {
   printer->Print(
-    "public static Builder newBuilder() { return new Builder(); }\n"
-    "public Builder newBuilderForType() { return new Builder(); }\n"
+    "public static Builder newBuilder() { return Builder.create(); }\n"
+    "public Builder newBuilderForType() { return newBuilder(); }\n"
     "public static Builder newBuilder($classname$ prototype) {\n"
-    "  return new Builder().mergeFrom(prototype);\n"
+    "  return newBuilder().mergeFrom(prototype);\n"
     "}\n"
     "public Builder toBuilder() { return newBuilder(this); }\n"
     "\n",
     "classname", ClassName(descriptor_));
 
   if (descriptor_->extension_range_count() > 0) {
-    printer->Print(
-      "public static final class Builder extends\n"
-      "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
-      "      $classname$, Builder> {\n",
-      "classname", ClassName(descriptor_));
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public static final class Builder extends\n"
+        "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+        "      $classname$, Builder> {\n",
+        "classname", ClassName(descriptor_));
+    } else {
+      printer->Print(
+        "public static final class Builder extends\n"
+        "    com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
+        "      $classname$, Builder> {\n",
+        "classname", ClassName(descriptor_));
+    }
   } else {
-    printer->Print(
-      "public static final class Builder extends\n"
-      "    com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
-      "classname", ClassName(descriptor_));
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public static final class Builder extends\n"
+        "    com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
+        "classname", ClassName(descriptor_));
+    } else {
+      printer->Print(
+        "public static final class Builder extends\n"
+        "    com.google.protobuf.GeneratedMessageLite.Builder<\n"
+        "      $classname$, Builder> {\n",
+        "classname", ClassName(descriptor_));
+    }
   }
   printer->Indent();
 
+  // By using a threadlocal queue, we do not have to worry about locking when
+  // accessing the queue.  Current JDKs implement this very efficiently, using
+  // no locks themselves to acquire the value when needed.
+  printer->Print(
+    "private static final "
+    "  com.google.protobuf.Internal.ThreadLocalQuickQueue<Builder> builders =\n"
+    "    new com.google.protobuf.Internal.ThreadLocalQuickQueue<Builder>();\n"
+    "\n");
+
   GenerateCommonBuilderMethods(printer);
 
-  if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (HasGeneratedMethods(descriptor_)) {
     GenerateBuilderParsingMethods(printer);
   }
 
@@ -553,10 +634,19 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
 
 void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
   printer->Print(
+    "private $classname$ result;\n"
+    "\n"
     "// Construct using $classname$.newBuilder()\n"
     "private Builder() {}\n"
     "\n"
-    "$classname$ result = new $classname$();\n"
+    "private static Builder create() {\n"
+    "  Builder builder = builders.get().poll();\n"
+    "  if (builder == null) {\n"
+    "    builder = new Builder();\n"
+    "  }\n"
+    "  builder.result = new $classname$();\n"
+    "  return builder;\n"
+    "}\n"
     "\n"
     "@Override\n"
     "protected $classname$ internalGetResult() {\n"
@@ -565,25 +655,38 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
     "\n"
     "@Override\n"
     "public Builder clear() {\n"
+    "  if (result == null) {\n"
+    "    throw new IllegalStateException(\n"
+    "      \"Cannot call clear() after build().\");\n"
+    "  }\n"
     "  result = new $classname$();\n"
     "  return this;\n"
     "}\n"
     "\n"
     "@Override\n"
     "public Builder clone() {\n"
-    "  return new Builder().mergeFrom(result);\n"
+    "  return create().mergeFrom(result);\n"
     "}\n"
-    "\n"
-    "@Override\n"
-    "public com.google.protobuf.Descriptors.Descriptor\n"
-    "    getDescriptorForType() {\n"
-    "  return $classname$.getDescriptor();\n"
-    "}\n"
-    "\n"
+    "\n",
+    "classname", ClassName(descriptor_));
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "@Override\n"
+      "public com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptorForType() {\n"
+      "  return $classname$.getDescriptor();\n"
+      "}\n"
+      "\n",
+      "classname", ClassName(descriptor_));
+  }
+  printer->Print(
     "public $classname$ getDefaultInstanceForType() {\n"
     "  return $classname$.getDefaultInstance();\n"
     "}\n"
-    "\n",
+    "\n"
+    "public boolean isInitialized() {\n"
+    "  return result.isInitialized();\n"
+    "}\n",
     "classname", ClassName(descriptor_));
 
   // -----------------------------------------------------------------
@@ -592,8 +695,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
     "public $classname$ build() {\n"
     // If result == null, we'll throw an appropriate exception later.
     "  if (result != null && !isInitialized()) {\n"
-    "    throw new com.google.protobuf.UninitializedMessageException(\n"
-    "      result);\n"
+    "    throw newUninitializedMessageException(result);\n"
     "  }\n"
     "  return buildPartial();\n"
     "}\n"
@@ -601,7 +703,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
     "private $classname$ buildParsed()\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
     "  if (!isInitialized()) {\n"
-    "    throw new com.google.protobuf.UninitializedMessageException(\n"
+    "    throw newUninitializedMessageException(\n"
     "      result).asInvalidProtocolBufferException();\n"
     "  }\n"
     "  return buildPartial();\n"
@@ -610,7 +712,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
     "public $classname$ buildPartial() {\n"
     "  if (result == null) {\n"
     "    throw new IllegalStateException(\n"
-    "      \"build() has already been called on this Builder.\");"
+    "      \"build() has already been called on this Builder.\");\n"
     "  }\n",
     "classname", ClassName(descriptor_));
   printer->Indent();
@@ -623,6 +725,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
   printer->Print(
     "  $classname$ returnMe = result;\n"
     "  result = null;\n"
+    "  builders.get().offer(this);\n"
     "  return returnMe;\n"
     "}\n"
     "\n",
@@ -630,18 +733,25 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
 
   // -----------------------------------------------------------------
 
-  if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+  if (HasGeneratedMethods(descriptor_)) {
+    // MergeFrom(Message other) requires the ability to distinguish the other
+    // messages type by its descriptor.
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "@Override\n"
+        "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
+        "  if (other instanceof $classname$) {\n"
+        "    return mergeFrom(($classname$)other);\n"
+        "  } else {\n"
+        "    super.mergeFrom(other);\n"
+        "    return this;\n"
+        "  }\n"
+        "}\n"
+        "\n",
+        "classname", ClassName(descriptor_));
+    }
+
     printer->Print(
-      "@Override\n"
-      "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
-      "  if (other instanceof $classname$) {\n"
-      "    return mergeFrom(($classname$)other);\n"
-      "  } else {\n"
-      "    super.mergeFrom(other);\n"
-      "    return this;\n"
-      "  }\n"
-      "}\n"
-      "\n"
       "public Builder mergeFrom($classname$ other) {\n"
       // Optimization:  If other is the default instance, we know none of its
       //   fields are set so we can skip the merge.
@@ -661,8 +771,12 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
         "  this.mergeExtensionFields(other);\n");
     }
 
+    if (HasUnknownFields(descriptor_)) {
+      printer->Print(
+        "  this.mergeUnknownFields(other.getUnknownFields());\n");
+    }
+
     printer->Print(
-      "  this.mergeUnknownFields(other.getUnknownFields());\n"
       "  return this;\n"
       "}\n"
       "\n");
@@ -676,25 +790,21 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
     SortFieldsByNumber(descriptor_));
 
   printer->Print(
-    "@Override\n"
-    "public Builder mergeFrom(\n"
-    "    com.google.protobuf.CodedInputStream input)\n"
-    "    throws java.io.IOException {\n"
-    "  return mergeFrom(input,\n"
-    "    com.google.protobuf.ExtensionRegistry.getEmptyRegistry());\n"
-    "}\n"
-    "\n"
     "@Override\n"
     "public Builder mergeFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
-    "    com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n");
   printer->Indent();
 
+  if (HasUnknownFields(descriptor_)) {
+    printer->Print(
+      "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+      "  com.google.protobuf.UnknownFieldSet.newBuilder(\n"
+      "    this.getUnknownFields());\n");
+  }
+
   printer->Print(
-    "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
-    "  com.google.protobuf.UnknownFieldSet.newBuilder(\n"
-    "    this.getUnknownFields());\n"
     "while (true) {\n");
   printer->Indent();
 
@@ -703,22 +813,34 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
     "switch (tag) {\n");
   printer->Indent();
 
-  printer->Print(
-    "case 0:\n"          // zero signals EOF / limit reached
-    "  this.setUnknownFields(unknownFields.build());\n"
-    "  return this;\n"
-    "default: {\n"
-    "  if (!parseUnknownField(input, unknownFields,\n"
-    "                         extensionRegistry, tag)) {\n"
-    "    this.setUnknownFields(unknownFields.build());\n"
-    "    return this;\n"   // it's an endgroup tag
-    "  }\n"
-    "  break;\n"
-    "}\n");
+  if (HasUnknownFields(descriptor_)) {
+    printer->Print(
+      "case 0:\n"          // zero signals EOF / limit reached
+      "  this.setUnknownFields(unknownFields.build());\n"
+      "  return this;\n"
+      "default: {\n"
+      "  if (!parseUnknownField(input, unknownFields,\n"
+      "                         extensionRegistry, tag)) {\n"
+      "    this.setUnknownFields(unknownFields.build());\n"
+      "    return this;\n"   // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
+  } else {
+    printer->Print(
+      "case 0:\n"          // zero signals EOF / limit reached
+      "  return this;\n"
+      "default: {\n"
+      "  if (!parseUnknownField(input, extensionRegistry, tag)) {\n"
+      "    return this;\n"   // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
+  }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = sorted_fields[i];
-    uint32 tag = WireFormat::MakeTag(field->number(),
+    uint32 tag = WireFormatLite::MakeTag(field->number(),
       WireFormat::WireTypeForField(field));
 
     printer->Print(

+ 22 - 81
src/google/protobuf/compiler/java/java_primitive_field.cc

@@ -39,9 +39,8 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format_inl.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
@@ -49,6 +48,7 @@ namespace compiler {
 namespace java {
 
 using internal::WireFormat;
+using internal::WireFormatLite;
 
 namespace {
 
@@ -121,16 +121,6 @@ const char* GetCapitalizedType(const FieldDescriptor* field) {
   return NULL;
 }
 
-bool AllPrintableAscii(const string& text) {
-  // Cannot use isprint() because it's locale-specific.  :(
-  for (int i = 0; i < text.size(); i++) {
-    if ((text[i] < 0x20) || text[i] >= 0x7F) {
-      return false;
-    }
-  }
-  return true;
-}
-
 // For encodings with fixed sizes, returns that size in bytes.  Otherwise
 // returns -1.
 int FixedSize(FieldDescriptor::Type type) {
@@ -141,14 +131,14 @@ int FixedSize(FieldDescriptor::Type type) {
     case FieldDescriptor::TYPE_UINT64  : return -1;
     case FieldDescriptor::TYPE_SINT32  : return -1;
     case FieldDescriptor::TYPE_SINT64  : return -1;
-    case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size;
-    case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
-    case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
-    case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
-    case FieldDescriptor::TYPE_FLOAT   : return WireFormat::kFloatSize;
-    case FieldDescriptor::TYPE_DOUBLE  : return WireFormat::kDoubleSize;
-
-    case FieldDescriptor::TYPE_BOOL    : return WireFormat::kBoolSize;
+    case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT   : return WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE  : return WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL    : return WireFormatLite::kBoolSize;
     case FieldDescriptor::TYPE_ENUM    : return -1;
 
     case FieldDescriptor::TYPE_STRING  : return -1;
@@ -163,64 +153,6 @@ int FixedSize(FieldDescriptor::Type type) {
   return -1;
 }
 
-string DefaultValue(const FieldDescriptor* field) {
-  // Switch on cpp_type since we need to know which default_value_* method
-  // of FieldDescriptor to call.
-  switch (field->cpp_type()) {
-    case FieldDescriptor::CPPTYPE_INT32:
-      return SimpleItoa(field->default_value_int32());
-    case FieldDescriptor::CPPTYPE_UINT32:
-      // Need to print as a signed int since Java has no unsigned.
-      return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
-    case FieldDescriptor::CPPTYPE_INT64:
-      return SimpleItoa(field->default_value_int64()) + "L";
-    case FieldDescriptor::CPPTYPE_UINT64:
-      return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
-             "L";
-    case FieldDescriptor::CPPTYPE_DOUBLE:
-      return SimpleDtoa(field->default_value_double()) + "D";
-    case FieldDescriptor::CPPTYPE_FLOAT:
-      return SimpleFtoa(field->default_value_float()) + "F";
-    case FieldDescriptor::CPPTYPE_BOOL:
-      return field->default_value_bool() ? "true" : "false";
-    case FieldDescriptor::CPPTYPE_STRING: {
-      bool isBytes = field->type() == FieldDescriptor::TYPE_BYTES;
-
-      if (!isBytes && AllPrintableAscii(field->default_value_string())) {
-        // All chars are ASCII and printable.  In this case CEscape() works
-        // fine (it will only escape quotes and backslashes).
-        // Note:  If this "optimization" is removed, DescriptorProtos will
-        //   no longer be able to initialize itself due to bootstrapping
-        //   problems.
-        return "\"" + CEscape(field->default_value_string()) + "\"";
-      }
-
-      if (isBytes && !field->has_default_value()) {
-        return "com.google.protobuf.ByteString.EMPTY";
-      }
-
-      // Escaping strings correctly for Java and generating efficient
-      // initializers for ByteStrings are both tricky.  We can sidestep the
-      // whole problem by just grabbing the default value from the descriptor.
-      return strings::Substitute(
-        "(($0) $1.getDescriptor().getFields().get($2).getDefaultValue())",
-        isBytes ? "com.google.protobuf.ByteString" : "java.lang.String",
-        ClassName(field->containing_type()), field->index());
-    }
-
-    case FieldDescriptor::CPPTYPE_ENUM:
-    case FieldDescriptor::CPPTYPE_MESSAGE:
-      GOOGLE_LOG(FATAL) << "Can't get here.";
-      return "";
-
-    // No default because we want the compiler to complain if any new
-    // types are added.
-  }
-
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
-}
-
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
                            map<string, string>* variables) {
   (*variables)["name"] =
@@ -285,8 +217,17 @@ GenerateBuilderMembers(io::Printer* printer) const {
     "  return this;\n"
     "}\n"
     "public Builder clear$capitalized_name$() {\n"
-    "  result.has$capitalized_name$ = false;\n"
-    "  result.$name$_ = $default$;\n"
+    "  result.has$capitalized_name$ = false;\n");
+  if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    // The default value is not a simple literal so we want to avoid executing
+    // it multiple times.  Instead, get the default out of the default instance.
+    printer->Print(variables_,
+      "  result.$name$_ = getDefaultInstance().get$capitalized_name$();\n");
+  } else {
+    printer->Print(variables_,
+      "  result.$name$_ = $default$;\n");
+  }
+  printer->Print(variables_,
     "  return this;\n"
     "}\n");
 }
@@ -355,7 +296,7 @@ GenerateMembers(io::Printer* printer) const {
     "}\n");
 
   if (descriptor_->options().packed() &&
-      descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+      HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
   }

+ 1 - 1
src/google/protobuf/compiler/parser.cc

@@ -661,7 +661,7 @@ bool Parser::ParseOptionAssignment(Message* options) {
   GOOGLE_CHECK(uninterpreted_option_field != NULL)
       << "No field named \"uninterpreted_option\" in the Options proto.";
 
-  UninterpretedOption* uninterpreted_option = ::google::protobuf::down_cast<UninterpretedOption*>(
+  UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
       options->GetReflection()->AddMessage(options,
                                            uninterpreted_option_field));
 

+ 66 - 14
src/google/protobuf/descriptor.cc

@@ -798,7 +798,7 @@ namespace {
 
 EncodedDescriptorDatabase* generated_database_ = NULL;
 DescriptorPool* generated_pool_ = NULL;
-GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_);
+GoogleOnceType generated_pool_init_;
 
 void DeleteGeneratedPool() {
   delete generated_database_;
@@ -814,7 +814,7 @@ void InitGeneratedPool() {
 }
 
 inline void InitGeneratedPoolOnce() {
-  GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
+  ::google::protobuf::GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
 }
 
 }  // anonymous namespace
@@ -1859,7 +1859,11 @@ class DescriptorBuilder {
   // dependency of this file, it will fail, but will set
   // possible_undeclared_dependency_ to point at that file.  This is only used
   // by AddNotDefinedError() to report a more useful error message.
+  // possible_undeclared_dependency_name_ is the name of the symbol that was
+  // actually found in possible_undeclared_dependency_, which may be a parent
+  // of the symbol actually looked for.
   const FileDescriptor* possible_undeclared_dependency_;
+  string possible_undeclared_dependency_name_;
 
   void AddError(const string& element_name,
                 const Message& descriptor,
@@ -2062,7 +2066,7 @@ class DescriptorBuilder {
                                 Message* options);
 
     // A recursive helper function that drills into the intermediate fields
-    // in unknown_fields to check if field #field_number is set on the
+    // in unknown_fields to check if field innermost_field is set on the
     // innermost message. Returns false and sets an error if so.
     bool ExamineIfOptionIsSet(
         vector<const FieldDescriptor*>::const_iterator intermediate_fields_iter,
@@ -2233,8 +2237,9 @@ void DescriptorBuilder::AddNotDefinedError(
              "\"" + undefined_symbol + "\" is not defined.");
   } else {
     AddError(element_name, descriptor, location,
-             "\"" + undefined_symbol + "\" seems to be defined in \""
-             + possible_undeclared_dependency_->name() + "\", which is not "
+             "\"" + possible_undeclared_dependency_name_ +
+             "\" seems to be defined in \"" +
+             possible_undeclared_dependency_->name() + "\", which is not "
              "imported by \"" + filename_ + "\".  To use it here, please "
              "add the necessary import.");
   }
@@ -2295,11 +2300,16 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
     // symbol unless none of the dependencies define it.
     if (IsInPackage(file_, name)) return result;
     for (int i = 0; i < file_->dependency_count(); i++) {
-      if (IsInPackage(file_->dependency(i), name)) return result;
+      // Note:  A dependency may be NULL if it was not found or had errors.
+      if (file_->dependency(i) != NULL &&
+          IsInPackage(file_->dependency(i), name)) {
+        return result;
+      }
     }
   }
 
   possible_undeclared_dependency_ = file;
+  possible_undeclared_dependency_name_ = name;
   return kNullSymbol;
 }
 
@@ -3592,12 +3602,38 @@ void DescriptorBuilder::CrossLinkMethod(
                             proto.array_name(i));                  \
   }
 
+// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to
+// avoid problems that exist at init time.
+static bool IsLite(const FileDescriptor* file) {
+  // TODO(kenton):  I don't even remember how many of these conditions are
+  //   actually possible.  I'm just being super-safe.
+  return file != NULL &&
+         &file->options() != NULL &&
+         &file->options() != &FileOptions::default_instance() &&
+         file->options().optimize_for() == FileOptions::LITE_RUNTIME;
+}
+
 void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file,
                                             const FileDescriptorProto& proto) {
   VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message);
   VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum);
   VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service);
   VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field);
+
+  // Lite files can only be imported by other Lite files.
+  if (!IsLite(file)) {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      if (IsLite(file->dependency(i))) {
+        AddError(
+          file->name(), proto,
+          DescriptorPool::ErrorCollector::OTHER,
+          "Files that do not use optimize_for = LITE_RUNTIME cannot import "
+          "files which do use this option.  This file is not lite, but it "
+          "imports \"" + file->dependency(i)->name() + "\" which is.");
+        break;
+      }
+    }
+  }
 }
 
 void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
@@ -3647,6 +3683,17 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
                "MessageSets cannot have fields, only extensions.");
     }
   }
+
+  // Lite extensions can only be of Lite types.
+  if (IsLite(field->file()) &&
+      field->containing_type_ != NULL &&
+      !IsLite(field->containing_type()->file())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::EXTENDEE,
+             "Extensions to non-lite types can only be declared in non-lite "
+             "files.  Note that you cannot extend a non-lite type to contain "
+             "a lite type, but the reverse is allowed.");
+  }
 }
 
 void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
@@ -3660,6 +3707,12 @@ void DescriptorBuilder::ValidateEnumValueOptions(
 }
 void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service,
     const ServiceDescriptorProto& proto) {
+  if (IsLite(service->file())) {
+    AddError(service->full_name(), proto,
+             DescriptorPool::ErrorCollector::NAME,
+             "Files with optimize_for = LITE_RUNTIME cannot define services.");
+  }
+
   VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
 }
 
@@ -3761,7 +3814,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
   const int num_uninterpreted_options = original_options->GetReflection()->
       FieldSize(*original_options, original_uninterpreted_options_field);
   for (int i = 0; i < num_uninterpreted_options; ++i) {
-    uninterpreted_option_ = ::google::protobuf::down_cast<const UninterpretedOption*>(
+    uninterpreted_option_ = down_cast<const UninterpretedOption*>(
         &original_options->GetReflection()->GetRepeatedMessage(
             *original_options, original_uninterpreted_options_field, i));
     if (!InterpretSingleOption(options)) {
@@ -4009,14 +4062,13 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
       const UnknownField* unknown_field = &unknown_fields.field(i);
       FieldDescriptor::Type type = (*intermediate_fields_iter)->type();
       // Recurse into the next submessage.
-      ++intermediate_fields_iter;
       switch (type) {
         case FieldDescriptor::TYPE_MESSAGE:
           if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) {
             UnknownFieldSet intermediate_unknown_fields;
             if (intermediate_unknown_fields.ParseFromString(
                     unknown_field->length_delimited()) &&
-                !ExamineIfOptionIsSet(intermediate_fields_iter,
+                !ExamineIfOptionIsSet(intermediate_fields_iter + 1,
                                       intermediate_fields_end,
                                       innermost_field, debug_msg_name,
                                       intermediate_unknown_fields)) {
@@ -4027,7 +4079,7 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
 
         case FieldDescriptor::TYPE_GROUP:
           if (unknown_field->type() == UnknownField::TYPE_GROUP) {
-            if (!ExamineIfOptionIsSet(intermediate_fields_iter,
+            if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
                                       intermediate_fields_end,
                                       innermost_field, debug_msg_name,
                                       unknown_field->group())) {
@@ -4139,7 +4191,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
                              option_field->full_name() + "\".");
       }
       unknown_fields->AddFixed32(option_field->number(),
-          google::protobuf::internal::WireFormat::EncodeFloat(value));
+          google::protobuf::internal::WireFormatLite::EncodeFloat(value));
       break;
     }
 
@@ -4156,7 +4208,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
                              option_field->full_name() + "\".");
       }
       unknown_fields->AddFixed64(option_field->number(),
-          google::protobuf::internal::WireFormat::EncodeDouble(value));
+          google::protobuf::internal::WireFormatLite::EncodeDouble(value));
       break;
     }
 
@@ -4267,7 +4319,7 @@ void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value,
 
     case FieldDescriptor::TYPE_SINT32:
       unknown_fields->AddVarint(number,
-          google::protobuf::internal::WireFormat::ZigZagEncode32(value));
+          google::protobuf::internal::WireFormatLite::ZigZagEncode32(value));
       break;
 
     default:
@@ -4289,7 +4341,7 @@ void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value,
 
     case FieldDescriptor::TYPE_SINT64:
       unknown_fields->AddVarint(number,
-          google::protobuf::internal::WireFormat::ZigZagEncode64(value));
+          google::protobuf::internal::WireFormatLite::ZigZagEncode64(value));
       break;
 
     default:

Разница между файлами не показана из-за своего большого размера
+ 284 - 196
src/google/protobuf/descriptor.pb.cc


+ 125 - 72
src/google/protobuf/descriptor.pb.h

@@ -18,9 +18,10 @@
 #error regenerate this file with a newer version of protoc.
 #endif
 
-#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_reflection.h>
 
 namespace google {
 namespace protobuf {
@@ -69,11 +70,11 @@ enum FieldDescriptorProto_Type {
   FieldDescriptorProto_Type_TYPE_SINT32 = 17,
   FieldDescriptorProto_Type_TYPE_SINT64 = 18
 };
-LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
 LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
 const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
 const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
 
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
 inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) {
   return ::google::protobuf::internal::NameOfEnum(
     FieldDescriptorProto_Type_descriptor(), value);
@@ -88,11 +89,11 @@ enum FieldDescriptorProto_Label {
   FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
   FieldDescriptorProto_Label_LABEL_REPEATED = 3
 };
-LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
 LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
 const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
 const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
 
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
 inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) {
   return ::google::protobuf::internal::NameOfEnum(
     FieldDescriptorProto_Label_descriptor(), value);
@@ -104,13 +105,14 @@ inline bool FieldDescriptorProto_Label_Parse(
 }
 enum FileOptions_OptimizeMode {
   FileOptions_OptimizeMode_SPEED = 1,
-  FileOptions_OptimizeMode_CODE_SIZE = 2
+  FileOptions_OptimizeMode_CODE_SIZE = 2,
+  FileOptions_OptimizeMode_LITE_RUNTIME = 3
 };
-LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
 LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
 const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
-const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_CODE_SIZE;
+const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
 
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
 inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) {
   return ::google::protobuf::internal::NameOfEnum(
     FileOptions_OptimizeMode_descriptor(), value);
@@ -124,11 +126,11 @@ enum FieldOptions_CType {
   FieldOptions_CType_CORD = 1,
   FieldOptions_CType_STRING_PIECE = 2
 };
-LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
 LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
 const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD;
 const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
 
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
 inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) {
   return ::google::protobuf::internal::NameOfEnum(
     FieldOptions_CType_descriptor(), value);
@@ -187,8 +189,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -212,6 +213,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -277,8 +279,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -384,6 +385,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -449,8 +451,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -479,6 +480,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -544,8 +546,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -635,6 +636,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -700,8 +702,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -724,13 +725,17 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
   static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64;
   static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32;
   static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64;
+  static inline bool Type_IsValid(int value) {
+    return FieldDescriptorProto_Type_IsValid(value);
+  }
+  static const Type Type_MIN =
+    FieldDescriptorProto_Type_Type_MIN;
+  static const Type Type_MAX =
+    FieldDescriptorProto_Type_Type_MAX;
   static inline const ::google::protobuf::EnumDescriptor*
   Type_descriptor() {
     return FieldDescriptorProto_Type_descriptor();
   }
-  static inline bool Type_IsValid(int value) {
-    return FieldDescriptorProto_Type_IsValid(value);
-  }
   static inline const ::std::string& Type_Name(Type value) {
     return FieldDescriptorProto_Type_Name(value);
   }
@@ -738,22 +743,22 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
       Type* value) {
     return FieldDescriptorProto_Type_Parse(name, value);
   }
-  static const Type Type_MIN =
-    FieldDescriptorProto_Type_Type_MIN;
-  static const Type Type_MAX =
-    FieldDescriptorProto_Type_Type_MAX;
   
   typedef FieldDescriptorProto_Label Label;
   static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
   static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
   static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED;
+  static inline bool Label_IsValid(int value) {
+    return FieldDescriptorProto_Label_IsValid(value);
+  }
+  static const Label Label_MIN =
+    FieldDescriptorProto_Label_Label_MIN;
+  static const Label Label_MAX =
+    FieldDescriptorProto_Label_Label_MAX;
   static inline const ::google::protobuf::EnumDescriptor*
   Label_descriptor() {
     return FieldDescriptorProto_Label_descriptor();
   }
-  static inline bool Label_IsValid(int value) {
-    return FieldDescriptorProto_Label_IsValid(value);
-  }
   static inline const ::std::string& Label_Name(Label value) {
     return FieldDescriptorProto_Label_Name(value);
   }
@@ -761,10 +766,6 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
       Label* value) {
     return FieldDescriptorProto_Label_Parse(name, value);
   }
-  static const Label Label_MIN =
-    FieldDescriptorProto_Label_Label_MIN;
-  static const Label Label_MAX =
-    FieldDescriptorProto_Label_Label_MAX;
   
   // accessors -------------------------------------------------------
   
@@ -855,6 +856,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -920,8 +922,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -965,6 +966,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1030,8 +1032,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1072,6 +1073,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1137,8 +1139,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1182,6 +1183,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1247,8 +1249,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1305,6 +1306,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1370,21 +1372,25 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
   typedef FileOptions_OptimizeMode OptimizeMode;
   static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
   static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
+  static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME;
+  static inline bool OptimizeMode_IsValid(int value) {
+    return FileOptions_OptimizeMode_IsValid(value);
+  }
+  static const OptimizeMode OptimizeMode_MIN =
+    FileOptions_OptimizeMode_OptimizeMode_MIN;
+  static const OptimizeMode OptimizeMode_MAX =
+    FileOptions_OptimizeMode_OptimizeMode_MAX;
   static inline const ::google::protobuf::EnumDescriptor*
   OptimizeMode_descriptor() {
     return FileOptions_OptimizeMode_descriptor();
   }
-  static inline bool OptimizeMode_IsValid(int value) {
-    return FileOptions_OptimizeMode_IsValid(value);
-  }
   static inline const ::std::string& OptimizeMode_Name(OptimizeMode value) {
     return FileOptions_OptimizeMode_Name(value);
   }
@@ -1392,10 +1398,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
       OptimizeMode* value) {
     return FileOptions_OptimizeMode_Parse(name, value);
   }
-  static const OptimizeMode OptimizeMode_MIN =
-    FileOptions_OptimizeMode_OptimizeMode_MIN;
-  static const OptimizeMode OptimizeMode_MAX =
-    FileOptions_OptimizeMode_OptimizeMode_MAX;
   
   // accessors -------------------------------------------------------
   
@@ -1459,6 +1461,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1524,8 +1527,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1538,6 +1540,13 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
   inline bool message_set_wire_format() const;
   inline void set_message_set_wire_format(bool value);
   
+  // optional bool no_standard_descriptor_accessor = 2 [default = false];
+  inline bool has_no_standard_descriptor_accessor() const;
+  inline void clear_no_standard_descriptor_accessor();
+  static const int kNoStandardDescriptorAccessorFieldNumber = 2;
+  inline bool no_standard_descriptor_accessor() const;
+  inline void set_no_standard_descriptor_accessor(bool value);
+  
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   inline int uninterpreted_option_size() const;
   inline void clear_uninterpreted_option();
@@ -1555,11 +1564,13 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
   mutable int _cached_size_;
   
   bool message_set_wire_format_;
+  bool no_standard_descriptor_accessor_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
-  ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+  
+  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
   inline bool _has_bit(int index) const {
@@ -1624,21 +1635,24 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
   typedef FieldOptions_CType CType;
   static const CType CORD = FieldOptions_CType_CORD;
   static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE;
+  static inline bool CType_IsValid(int value) {
+    return FieldOptions_CType_IsValid(value);
+  }
+  static const CType CType_MIN =
+    FieldOptions_CType_CType_MIN;
+  static const CType CType_MAX =
+    FieldOptions_CType_CType_MAX;
   static inline const ::google::protobuf::EnumDescriptor*
   CType_descriptor() {
     return FieldOptions_CType_descriptor();
   }
-  static inline bool CType_IsValid(int value) {
-    return FieldOptions_CType_IsValid(value);
-  }
   static inline const ::std::string& CType_Name(CType value) {
     return FieldOptions_CType_Name(value);
   }
@@ -1646,10 +1660,6 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
       CType* value) {
     return FieldOptions_CType_Parse(name, value);
   }
-  static const CType CType_MIN =
-    FieldOptions_CType_CType_MIN;
-  static const CType CType_MAX =
-    FieldOptions_CType_CType_MAX;
   
   // accessors -------------------------------------------------------
   
@@ -1709,6 +1719,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1774,8 +1785,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1801,6 +1811,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1866,8 +1877,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1893,6 +1903,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1958,8 +1969,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -1985,6 +1995,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2050,8 +2061,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -2077,6 +2087,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2142,8 +2153,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -2176,6 +2186,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2241,8 +2252,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
   void SetCachedSize(int size) const { _cached_size_ = size; }
   public:
   
-  const ::google::protobuf::Descriptor* GetDescriptor() const;
-  const ::google::protobuf::Reflection* GetReflection() const;
+  ::google::protobuf::Metadata GetMetadata() const;
   
   // nested types ----------------------------------------------------
   
@@ -2316,6 +2326,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+  
   ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -3647,6 +3658,22 @@ inline void MessageOptions::set_message_set_wire_format(bool value) {
   message_set_wire_format_ = value;
 }
 
+// optional bool no_standard_descriptor_accessor = 2 [default = false];
+inline bool MessageOptions::has_no_standard_descriptor_accessor() const {
+  return _has_bit(1);
+}
+inline void MessageOptions::clear_no_standard_descriptor_accessor() {
+  no_standard_descriptor_accessor_ = false;
+  _clear_bit(1);
+}
+inline bool MessageOptions::no_standard_descriptor_accessor() const {
+  return no_standard_descriptor_accessor_;
+}
+inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
+  _set_bit(1);
+  no_standard_descriptor_accessor_ = value;
+}
+
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
 inline int MessageOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
@@ -4134,4 +4161,30 @@ inline ::std::string* UninterpretedOption::mutable_string_value() {
 
 }  // namespace protobuf
 }  // namespace google
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Type>() {
+  return ::google::protobuf::FieldDescriptorProto_Type_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Label>() {
+  return ::google::protobuf::FieldDescriptorProto_Label_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FileOptions_OptimizeMode>() {
+  return ::google::protobuf::FileOptions_OptimizeMode_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() {
+  return ::google::protobuf::FieldOptions_CType_descriptor();
+}
+
+}  // namespace google
+}  // namespace protobuf
+#endif  // SWIG
+
 #endif  // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED

+ 9 - 2
src/google/protobuf/descriptor.proto

@@ -247,8 +247,10 @@ message FileOptions {
 
   // Generated classes can be optimized for speed or code size.
   enum OptimizeMode {
-    SPEED = 1;      // Generate complete code for parsing, serialization, etc.
-    CODE_SIZE = 2;  // Use ReflectionOps to implement these methods.
+    SPEED = 1;        // Generate complete code for parsing, serialization,
+                      // etc.
+    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
   }
   optional OptimizeMode optimize_for = 9 [default=SPEED];
 
@@ -282,6 +284,11 @@ message MessageOptions {
   // the protocol compiler.
   optional bool message_set_wire_format = 1 [default=false];
 
+  // Disables the generation of the standard "descriptor()" accessor, which can
+  // conflict with a field of the same name.  This is meant to make migration
+  // from proto1 easier; new code should avoid fields named "descriptor".
+  optional bool no_standard_descriptor_accessor = 2 [default=false];
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 

+ 145 - 0
src/google/protobuf/descriptor_unittest.cc

@@ -2135,6 +2135,83 @@ TEST(CustomOptions, OptionsFromOtherFile) {
   EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
 }
 
+TEST(CustomOptions, MessageOptionThreeFieldsSet) {
+  // This tests a bug which previously existed in custom options parsing.  The
+  // bug occurred when you defined a custom option with message type and then
+  // set three fields of that option on a single definition (see the example
+  // below).  The bug is a bit hard to explain, so check the change history if
+  // you want to know more.
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()
+    ->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // The following represents the definition:
+  //
+  //   import "google/protobuf/unittest_custom_options.proto"
+  //   package protobuf_unittest;
+  //   message Foo {
+  //     option (complex_opt1).foo  = 1234;
+  //     option (complex_opt1).foo2 = 1234;
+  //     option (complex_opt1).foo3 = 1234;
+  //   }
+  ASSERT_TRUE(TextFormat::ParseFromString(
+    "name: \"custom_options_import.proto\" "
+    "package: \"protobuf_unittest\" "
+    "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+    "message_type { "
+    "  name: \"Foo\" "
+    "  options { "
+    "    uninterpreted_option { "
+    "      name { "
+    "        name_part: \"complex_opt1\" "
+    "        is_extension: true "
+    "      } "
+    "      name { "
+    "        name_part: \"foo\" "
+    "        is_extension: false "
+    "      } "
+    "      positive_int_value: 1234 "
+    "    } "
+    "    uninterpreted_option { "
+    "      name { "
+    "        name_part: \"complex_opt1\" "
+    "        is_extension: true "
+    "      } "
+    "      name { "
+    "        name_part: \"foo2\" "
+    "        is_extension: false "
+    "      } "
+    "      positive_int_value: 1234 "
+    "    } "
+    "    uninterpreted_option { "
+    "      name { "
+    "        name_part: \"complex_opt1\" "
+    "        is_extension: true "
+    "      } "
+    "      name { "
+    "        name_part: \"foo3\" "
+    "        is_extension: false "
+    "      } "
+    "      positive_int_value: 1234 "
+    "    } "
+    "  } "
+    "}",
+    &file_proto));
+
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != NULL);
+  ASSERT_EQ(1, file->message_type_count());
+
+  const MessageOptions& options = file->message_type(0)->options();
+  EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
+}
+
 
 // ===================================================================
 
@@ -2335,6 +2412,30 @@ TEST_F(ValidationErrorTest, UnknownDependency) {
     "bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
 }
 
+TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
+  // Used to crash:  If we depend on a non-existent file and then refer to a
+  // package defined in a file that we didn't import, and that package is
+  // nested within a parent package which this file is also in, and we don't
+  // include that parent package in the name (i.e. we do a relative lookup)...
+  // Yes, really.
+  BuildFile(
+    "name: 'foo.proto' "
+    "package: 'outer.foo' ");
+  BuildFileWithErrors(
+    "name: 'bar.proto' "
+    "dependency: 'baz.proto' "
+    "package: 'outer.bar' "
+    "message_type { "
+    "  name: 'Bar' "
+    "  field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
+    "}",
+
+    "bar.proto: bar.proto: OTHER: Import \"baz.proto\" has not been loaded.\n"
+    "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined in "
+      "\"foo.proto\", which is not imported by \"bar.proto\".  To use it here, "
+      "please add the necessary import.\n");
+}
+
 TEST_F(ValidationErrorTest, DupeFile) {
   BuildFile(
     "name: \"foo.proto\" "
@@ -3345,6 +3446,50 @@ TEST_F(ValidationErrorTest, TryingToSetMessageValuedOption) {
     "message type.\n");
 }
 
+TEST_F(ValidationErrorTest, NotLiteImportsLite) {
+  BuildFile(
+    "name: \"bar.proto\" "
+    "options { optimize_for: LITE_RUNTIME } ");
+
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "dependency: \"bar.proto\" ",
+
+    "foo.proto: foo.proto: OTHER: Files that do not use optimize_for = "
+      "LITE_RUNTIME cannot import files which do use this option.  This file "
+      "is not lite, but it imports \"bar.proto\" which is.\n");
+}
+
+TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
+  BuildFile(
+    "name: \"bar.proto\" "
+    "message_type: {"
+    "  name: \"Bar\""
+    "  extension_range { start: 1 end: 1000 }"
+    "}");
+
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "dependency: \"bar.proto\" "
+    "options { optimize_for: LITE_RUNTIME } "
+    "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
+    "            type: TYPE_INT32 extendee: \"Bar\" }",
+
+    "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
+      "declared in non-lite files.  Note that you cannot extend a non-lite "
+      "type to contain a lite type, but the reverse is allowed.\n");
+}
+
+TEST_F(ValidationErrorTest, NoLiteServices) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "options { optimize_for: LITE_RUNTIME } "
+    "service { name: \"Foo\" }",
+
+    "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
+    "define services.\n");
+}
+
 TEST_F(ValidationErrorTest, RollbackAfterError) {
   // Build a file which contains every kind of construct but references an
   // undefined type.  All these constructs will be added to the symbol table

+ 43 - 41
src/google/protobuf/dynamic_message.cc

@@ -70,6 +70,7 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/reflection_ops.h>
 #include <google/protobuf/repeated_field.h>
@@ -82,7 +83,6 @@ namespace protobuf {
 using internal::WireFormat;
 using internal::ExtensionSet;
 using internal::GeneratedMessageReflection;
-using internal::GenericRepeatedField;
 
 
 // ===================================================================
@@ -186,8 +186,7 @@ class DynamicMessage : public Message {
   int GetCachedSize() const;
   void SetCachedSize(int size) const;
 
-  const Descriptor* GetDescriptor() const;
-  const Reflection* GetReflection() const;
+  Metadata GetMetadata() const;
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
@@ -279,20 +278,10 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info)
         break;
 
       case FieldDescriptor::CPPTYPE_MESSAGE: {
-        // If this object is the prototype, its CPPTYPE_MESSAGE fields
-        // must be initialized later, in CrossLinkPrototypes(), so we don't
-        // initialize them here.
-        if (!is_prototype()) {
-          if (!field->is_repeated()) {
-            new(field_ptr) Message*(NULL);
-          } else {
-            const RepeatedPtrField<Message>* prototype_field =
-              reinterpret_cast<const RepeatedPtrField<Message>*>(
-                type_info_->prototype->OffsetToPointer(
-                  type_info_->offsets[i]));
-            new(field_ptr) RepeatedPtrField<Message>(
-              prototype_field->prototype());
-          }
+        if (!field->is_repeated()) {
+          new(field_ptr) Message*(NULL);
+        } else {
+          new(field_ptr) RepeatedPtrField<Message>();
         }
         break;
       }
@@ -322,9 +311,33 @@ DynamicMessage::~DynamicMessage() {
     void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
 
     if (field->is_repeated()) {
-      GenericRepeatedField* field =
-        reinterpret_cast<GenericRepeatedField*>(field_ptr);
-      field->~GenericRepeatedField();
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+        case FieldDescriptor::CPPTYPE_##UPPERCASE :                           \
+          reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr)              \
+              ->~RepeatedField<LOWERCASE>();                                  \
+          break
+
+        HANDLE_TYPE( INT32,  int32);
+        HANDLE_TYPE( INT64,  int64);
+        HANDLE_TYPE(UINT32, uint32);
+        HANDLE_TYPE(UINT64, uint64);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE( FLOAT,  float);
+        HANDLE_TYPE(  BOOL,   bool);
+        HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+            reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
+                ->~RepeatedPtrField<string>();
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
+              ->~RepeatedPtrField<Message>();
+          break;
+      }
 
     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
         string* ptr = *reinterpret_cast<string**>(field_ptr);
@@ -353,24 +366,14 @@ void DynamicMessage::CrossLinkPrototypes() {
     const FieldDescriptor* field = descriptor->field(i);
     void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
 
-    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !field->is_repeated()) {
       // For fields with message types, we need to cross-link with the
       // prototype for the field's type.
-      const Message* field_prototype =
+      // For singular fields, the field is just a pointer which should
+      // point to the prototype.
+      *reinterpret_cast<const Message**>(field_ptr) =
         factory->GetPrototype(field->message_type());
-
-      if (field->is_repeated()) {
-        // For repeated fields, we actually construct the RepeatedPtrField
-        // here, but only for fields with message types.  All other repeated
-        // fields are constructed in DynamicMessage's constructor.
-        new(field_ptr) RepeatedPtrField<Message>(field_prototype);
-      } else {
-        // For singular fields, the field is just a pointer which should
-        // point to the prototype.  (OK to const_cast here because the
-        // prototype itself will only be available const to the outside
-        // world.)
-        new(field_ptr) Message*(const_cast<Message*>(field_prototype));
-      }
     }
   }
 }
@@ -392,12 +395,11 @@ void DynamicMessage::SetCachedSize(int size) const {
   cached_byte_size_ = size;
 }
 
-const Descriptor* DynamicMessage::GetDescriptor() const {
-  return type_info_->type;
-}
-
-const Reflection* DynamicMessage::GetReflection() const {
-  return type_info_->reflection.get();
+Metadata DynamicMessage::GetMetadata() const {
+  Metadata metadata;
+  metadata.descriptor = type_info_->type;
+  metadata.reflection = type_info_->reflection.get();
+  return metadata;
 }
 
 // ===================================================================

Разница между файлами не показана из-за своего большого размера
+ 361 - 232
src/google/protobuf/extension_set.cc


+ 97 - 47
src/google/protobuf/extension_set.h

@@ -45,20 +45,23 @@
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/message.h>
 
 namespace google {
+
 namespace protobuf {
   class Descriptor;                                    // descriptor.h
   class FieldDescriptor;                               // descriptor.h
   class DescriptorPool;                                // descriptor.h
-  class Message;                                       // message.h
+  class MessageLite;                                   // message_lite.h
   class MessageFactory;                                // message.h
   class UnknownFieldSet;                               // unknown_field_set.h
   namespace io {
     class CodedInputStream;                              // coded_stream.h
     class CodedOutputStream;                             // coded_stream.h
   }
+  namespace internal {
+    class FieldSkipper;                                  // wire_format_lite.h
+  }
   template <typename Element> class RepeatedField;     // repeated_field.h
   template <typename Element> class RepeatedPtrField;  // repeated_field.h
 }
@@ -66,9 +69,9 @@ namespace protobuf {
 namespace protobuf {
 namespace internal {
 
-// Used to store values of type FieldDescriptor::Type without having to
-// #include descriptor.h.  Also, ensures that we use only one byte to store
-// these values, which is important to keep the layout of
+// Used to store values of type WireFormatLite::FieldType without having to
+// #include wire_format_lite.h.  Also, ensures that we use only one byte to
+// store these values, which is important to keep the layout of
 // ExtensionSet::Extension small.
 typedef uint8 FieldType;
 
@@ -98,17 +101,17 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   // to look up extensions for parsed field numbers.  Note that dynamic parsing
   // does not use ParseField(); only protocol-compiler-generated parsing
   // methods do.
-  static void RegisterExtension(const Message* containing_type,
+  static void RegisterExtension(const MessageLite* containing_type,
                                 int number, FieldType type,
                                 bool is_repeated, bool is_packed);
-  static void RegisterEnumExtension(const Message* containing_type,
+  static void RegisterEnumExtension(const MessageLite* containing_type,
                                     int number, FieldType type,
                                     bool is_repeated, bool is_packed,
                                     EnumValidityFunc* is_valid);
-  static void RegisterMessageExtension(const Message* containing_type,
+  static void RegisterMessageExtension(const MessageLite* containing_type,
                                        int number, FieldType type,
                                        bool is_repeated, bool is_packed,
-                                       const Message* prototype);
+                                       const MessageLite* prototype);
 
   // =================================================================
 
@@ -167,9 +170,10 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   bool   GetBool  (int number, bool   default_value) const;
   int    GetEnum  (int number, int    default_value) const;
   const string & GetString (int number, const string&  default_value) const;
-  const Message& GetMessage(int number, const Message& default_value) const;
-  const Message& GetMessage(int number, const Descriptor* message_type,
-                            MessageFactory* factory) const;
+  const MessageLite& GetMessage(int number,
+                                const MessageLite& default_value) const;
+  const MessageLite& GetMessage(int number, const Descriptor* message_type,
+                                MessageFactory* factory) const;
 
   void SetInt32 (int number, FieldType type, int32  value);
   void SetInt64 (int number, FieldType type, int64  value);
@@ -181,11 +185,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   void SetEnum  (int number, FieldType type, int    value);
   void SetString(int number, FieldType type, const string& value);
   string * MutableString (int number, FieldType type);
-  Message* MutableMessage(int number, FieldType type,
-                          const Message& prototype);
-  Message* MutableMessage(int number, FieldType type,
-                          const Descriptor* message_type,
-                          MessageFactory* factory);
+  MessageLite* MutableMessage(int number, FieldType type,
+                              const MessageLite& prototype);
+  MessageLite* MutableMessage(int number, FieldType type,
+                              const Descriptor* message_type,
+                              MessageFactory* factory);
 
   // repeated fields -------------------------------------------------
 
@@ -198,7 +202,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   bool   GetRepeatedBool  (int number, int index) const;
   int    GetRepeatedEnum  (int number, int index) const;
   const string & GetRepeatedString (int number, int index) const;
-  const Message& GetRepeatedMessage(int number, int index) const;
+  const MessageLite& GetRepeatedMessage(int number, int index) const;
 
   void SetRepeatedInt32 (int number, int index, int32  value);
   void SetRepeatedInt64 (int number, int index, int64  value);
@@ -210,7 +214,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   void SetRepeatedEnum  (int number, int index, int    value);
   void SetRepeatedString(int number, int index, const string& value);
   string * MutableRepeatedString (int number, int index);
-  Message* MutableRepeatedMessage(int number, int index);
+  MessageLite* MutableRepeatedMessage(int number, int index);
 
   void AddInt32 (int number, FieldType type, bool packed, int32  value);
   void AddInt64 (int number, FieldType type, bool packed, int64  value);
@@ -222,11 +226,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   void AddEnum  (int number, FieldType type, bool packed, int    value);
   void AddString(int number, FieldType type, const string& value);
   string * AddString (int number, FieldType type);
-  Message* AddMessage(int number, FieldType type,
-                      const Message& prototype);
-  Message* AddMessage(int number, FieldType type,
-                      const Descriptor* message_type,
-                      MessageFactory* factory);
+  MessageLite* AddMessage(int number, FieldType type,
+                          const MessageLite& prototype);
+  MessageLite* AddMessage(int number, FieldType type,
+                          const Descriptor* message_type,
+                          MessageFactory* factory);
 
   void RemoveLast(int number);
   void SwapElements(int number, int index1, int index2);
@@ -252,9 +256,31 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   // methods of ExtensionSet, this only works for generated message types --
   // it looks up extensions registered using RegisterExtension().
   bool ParseField(uint32 tag, io::CodedInputStream* input,
-                  const Message* containing_type,
+                  const MessageLite* containing_type,
+                  FieldSkipper* field_skipper);
+
+  // Specific versions for lite or full messages (constructs the appropriate
+  // FieldSkipper automatically).
+  bool ParseField(uint32 tag, io::CodedInputStream* input,
+                  const MessageLite* containing_type);
+  bool ParseField(uint32 tag, io::CodedInputStream* input,
+                  const MessageLite* containing_type,
                   UnknownFieldSet* unknown_fields);
 
+  // Parse an entire message in MessageSet format.  Such messages have no
+  // fields, only extensions.
+  bool ParseMessageSet(io::CodedInputStream* input,
+                       const MessageLite* containing_type,
+                       FieldSkipper* field_skipper);
+
+  // Specific versions for lite or full messages (constructs the appropriate
+  // FieldSkipper automatically).
+  bool ParseMessageSet(io::CodedInputStream* input,
+                       const MessageLite* containing_type);
+  bool ParseMessageSet(io::CodedInputStream* input,
+                       const MessageLite* containing_type,
+                       UnknownFieldSet* unknown_fields);
+
   // Write all extension fields with field numbers in the range
   //   [start_field_number, end_field_number)
   // to the output stream, using the cached sizes computed when ByteSize() was
@@ -272,37 +298,50 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
                                          int end_field_number,
                                          uint8* target) const;
 
+  // Like above but serializes in MessageSet format.
+  void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
+  uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
+
   // Returns the total serialized size of all the extensions.
   int ByteSize() const;
 
+  // Like ByteSize() but uses MessageSet format.
+  int MessageSetByteSize() const;
+
   // Returns (an estimate of) the total number of bytes used for storing the
-  // extensions in memory, excluding sizeof(*this).
+  // extensions in memory, excluding sizeof(*this).  If the ExtensionSet is
+  // for a lite message (and thus possibly contains lite messages), the results
+  // are undefined (might work, might crash, might corrupt data, might not even
+  // be linked in).  It's up to the protocol compiler to avoid calling this on
+  // such ExtensionSets (easy enough since lite messages don't implement
+  // SpaceUsed()).
   int SpaceUsedExcludingSelf() const;
 
  private:
+
   struct Extension {
     union {
-      int32    int32_value;
-      int64    int64_value;
-      uint32   uint32_value;
-      uint64   uint64_value;
-      float    float_value;
-      double   double_value;
-      bool     bool_value;
-      int      enum_value;
-      string*  string_value;
-      Message* message_value;
-
-      RepeatedField   <int32  >* repeated_int32_value;
-      RepeatedField   <int64  >* repeated_int64_value;
-      RepeatedField   <uint32 >* repeated_uint32_value;
-      RepeatedField   <uint64 >* repeated_uint64_value;
-      RepeatedField   <float  >* repeated_float_value;
-      RepeatedField   <double >* repeated_double_value;
-      RepeatedField   <bool   >* repeated_bool_value;
-      RepeatedField   <int    >* repeated_enum_value;
-      RepeatedPtrField<string >* repeated_string_value;
-      RepeatedPtrField<Message>* repeated_message_value;
+      int32        int32_value;
+      int64        int64_value;
+      uint32       uint32_value;
+      uint64       uint64_value;
+      float        float_value;
+      double       double_value;
+      bool         bool_value;
+      int          enum_value;
+      string*      string_value;
+      MessageLite* message_value;
+
+      RepeatedField   <int32      >* repeated_int32_value;
+      RepeatedField   <int64      >* repeated_int64_value;
+      RepeatedField   <uint32     >* repeated_uint32_value;
+      RepeatedField   <uint64     >* repeated_uint64_value;
+      RepeatedField   <float      >* repeated_float_value;
+      RepeatedField   <double     >* repeated_double_value;
+      RepeatedField   <bool       >* repeated_bool_value;
+      RepeatedField   <int        >* repeated_enum_value;
+      RepeatedPtrField<string     >* repeated_string_value;
+      RepeatedPtrField<MessageLite>* repeated_message_value;
     };
 
     FieldType type;
@@ -328,7 +367,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
     void SerializeFieldWithCachedSizes(
         int number,
         io::CodedOutputStream* output) const;
+    void SerializeMessageSetItemWithCachedSizes(
+        int number,
+        io::CodedOutputStream* output) const;
     int ByteSize(int number) const;
+    int MessageSetItemByteSize(int number) const;
     void Clear();
     int GetSize() const;
     void Free();
@@ -339,6 +382,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
   // already exist.  Returns true if the extension did not already exist.
   bool MaybeNewExtension(int number, Extension** result);
 
+  // Parse a single MessageSet item -- called just after the item group start
+  // tag has been read.
+  bool ParseMessageSetItem(io::CodedInputStream* input,
+                           const MessageLite* containing_type,
+                           FieldSkipper* field_skipper);
+
+
   // The Extension struct is small enough to be passed by value, so we use it
   // directly as the value type in the map rather than use pointers.  We use
   // a map rather than hash_map here because we expect most ExtensionSets will

+ 218 - 0
src/google/protobuf/extension_set_heavy.cc

@@ -0,0 +1,218 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Contains methods defined in extension_set.h which cannot be part of the
+// lite library because they use descriptors or reflection.
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void ExtensionSet::AppendToList(const Descriptor* containing_type,
+                                const DescriptorPool* pool,
+                                vector<const FieldDescriptor*>* output) const {
+  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+       iter != extensions_.end(); ++iter) {
+    bool has = false;
+    if (iter->second.is_repeated) {
+      has = iter->second.GetSize() > 0;
+    } else {
+      has = !iter->second.is_cleared;
+    }
+
+    if (has) {
+      output->push_back(
+          pool->FindExtensionByNumber(containing_type, iter->first));
+    }
+  }
+}
+
+inline FieldDescriptor::CppType cpp_type(FieldType type) {
+  return FieldDescriptor::TypeToCppType(
+      static_cast<FieldDescriptor::Type>(type));
+}
+
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                            \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED     \
+                                  : FieldDescriptor::LABEL_OPTIONAL,      \
+            FieldDescriptor::LABEL_##LABEL);                              \
+  GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+const MessageLite& ExtensionSet::GetMessage(int number,
+                                            const Descriptor* message_type,
+                                            MessageFactory* factory) const {
+  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  if (iter == extensions_.end() || iter->second.is_cleared) {
+    // Not present.  Return the default value.
+    return *factory->GetPrototype(message_type);
+  } else {
+    GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+    return *iter->second.message_value;
+  }
+}
+
+MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
+                                          const Descriptor* message_type,
+                                          MessageFactory* factory) {
+  Extension* extension;
+  if (MaybeNewExtension(number, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_packed = false;
+    const MessageLite* prototype = factory->GetPrototype(message_type);
+    GOOGLE_CHECK(prototype != NULL);
+    extension->message_value = prototype->New();
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+  }
+  extension->is_cleared = false;
+  return extension->message_value;
+}
+
+MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
+                                      const Descriptor* message_type,
+                                      MessageFactory* factory) {
+  Extension* extension;
+  if (MaybeNewExtension(number, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
+    extension->is_repeated = true;
+    extension->repeated_message_value =
+      new RepeatedPtrField<MessageLite>();
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
+  }
+
+  // RepeatedPtrField<Message> does not know how to Add() since it cannot
+  // allocate an abstract object, so we have to be tricky.
+  MessageLite* result = extension->repeated_message_value
+      ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
+  if (result == NULL) {
+    const MessageLite* prototype;
+    if (extension->repeated_message_value->size() == 0) {
+      prototype = factory->GetPrototype(message_type);
+      GOOGLE_CHECK(prototype != NULL);
+    } else {
+      prototype = &extension->repeated_message_value->Get(0);
+    }
+    result = prototype->New();
+    extension->repeated_message_value->AddAllocated(result);
+  }
+  return result;
+}
+
+bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+                              const MessageLite* containing_type,
+                              UnknownFieldSet* unknown_fields) {
+  UnknownFieldSetFieldSkipper skipper(unknown_fields);
+  return ParseField(tag, input, containing_type, &skipper);
+}
+
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
+                                   const MessageLite* containing_type,
+                                   UnknownFieldSet* unknown_fields) {
+  UnknownFieldSetFieldSkipper skipper(unknown_fields);
+  return ParseMessageSet(input, containing_type, &skipper);
+}
+
+int ExtensionSet::SpaceUsedExcludingSelf() const {
+  int total_size =
+      extensions_.size() * sizeof(map<int, Extension>::value_type);
+  for (map<int, Extension>::const_iterator iter = extensions_.begin(),
+       end = extensions_.end();
+       iter != end;
+       ++iter) {
+    total_size += iter->second.SpaceUsedExcludingSelf();
+  }
+  return total_size;
+}
+
+int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
+  int total_size = 0;
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                          \
+      case WireFormatLite::CPPTYPE_##UPPERCASE:                    \
+        total_size += sizeof(*repeated_##LOWERCASE##_value) +      \
+            repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\
+        break
+
+      HANDLE_TYPE(  INT32,   int32);
+      HANDLE_TYPE(  INT64,   int64);
+      HANDLE_TYPE( UINT32,  uint32);
+      HANDLE_TYPE( UINT64,  uint64);
+      HANDLE_TYPE(  FLOAT,   float);
+      HANDLE_TYPE( DOUBLE,  double);
+      HANDLE_TYPE(   BOOL,    bool);
+      HANDLE_TYPE(   ENUM,    enum);
+      HANDLE_TYPE( STRING,  string);
+
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        // repeated_message_value is actually a RepeatedPtrField<MessageLite>,
+        // but MessageLite has no SpaceUsed(), so we must directly call
+        // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type
+        // handler.
+        total_size += sizeof(*repeated_message_value) +
+            repeated_message_value->
+              RepeatedPtrFieldBase::SpaceUsedExcludingSelf<
+                GenericTypeHandler<Message> >();
+        break;
+    }
+  } else {
+    switch (cpp_type(type)) {
+      case WireFormatLite::CPPTYPE_STRING:
+        total_size += sizeof(*string_value) +
+                      StringSpaceUsedExcludingSelf(*string_value);
+        break;
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        total_size += down_cast<Message*>(message_value)->SpaceUsed();
+        break;
+      default:
+        // No extra storage costs for primitive types.
+        break;
+    }
+  }
+  return total_size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google

+ 243 - 58
src/google/protobuf/generated_message_reflection.cc

@@ -38,6 +38,7 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -220,8 +221,36 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const {
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (field->is_repeated()) {
-      total_size += GetRaw<GenericRepeatedField>(message, field)
-                      .GenericSpaceUsedExcludingSelf();
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+        case FieldDescriptor::CPPTYPE_##UPPERCASE :                           \
+          total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field)     \
+                          .SpaceUsedExcludingSelf();                          \
+          break
+
+        HANDLE_TYPE( INT32,  int32);
+        HANDLE_TYPE( INT64,  int64);
+        HANDLE_TYPE(UINT32, uint32);
+        HANDLE_TYPE(UINT64, uint64);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE( FLOAT,  float);
+        HANDLE_TYPE(  BOOL,   bool);
+        HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+            total_size += GetRaw<RepeatedPtrField<string> >(message, field)
+                            .SpaceUsedExcludingSelf();
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          // We don't know which subclass of RepeatedPtrFieldBase the type is,
+          // so we use RepeatedPtrFieldBase directly.
+          total_size +=
+              GetRaw<RepeatedPtrFieldBase>(message, field)
+                .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
+          break;
+      }
     } else {
       switch (field->cpp_type()) {
         case FieldDescriptor::CPPTYPE_INT32 :
@@ -274,25 +303,59 @@ void GeneratedMessageReflection::Swap(
     Message* message2) const {
   if (message1 == message2) return;
 
+  // TODO(kenton):  Other Reflection methods should probably check this too.
   GOOGLE_CHECK_EQ(message1->GetReflection(), this)
-    << "Tried to swap using reflection object incompatible with message1.";
-
+    << "First argument to Swap() (of type \""
+    << message1->GetDescriptor()->full_name()
+    << "\") is not compatible with this reflection object (which is for type \""
+    << descriptor_->full_name()
+    << "\").  Note that the exact same class is required; not just the same "
+       "descriptor.";
   GOOGLE_CHECK_EQ(message2->GetReflection(), this)
-    << "Tried to swap using reflection object incompatible with message2.";
+    << "Second argument to Swap() (of type \""
+    << message1->GetDescriptor()->full_name()
+    << "\") is not compatible with this reflection object (which is for type \""
+    << descriptor_->full_name()
+    << "\").  Note that the exact same class is required; not just the same "
+       "descriptor.";
 
   uint32* has_bits1 = MutableHasBits(message1);
   uint32* has_bits2 = MutableHasBits(message2);
   int has_bits_size = (descriptor_->field_count() + 31) / 32;
 
   for (int i = 0; i < has_bits_size; i++) {
-    std::swap(has_bits1[i], has_bits2[i]);
+    swap(has_bits1[i], has_bits2[i]);
   }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     if (field->is_repeated()) {
-      MutableRaw<GenericRepeatedField>(message1, field)->GenericSwap(
-          MutableRaw<GenericRepeatedField>(message2, field));
+      switch (field->cpp_type()) {
+#define SWAP_ARRAYS(CPPTYPE, TYPE)                                           \
+        case FieldDescriptor::CPPTYPE_##CPPTYPE:                             \
+          MutableRaw<RepeatedField<TYPE> >(message1, field)->Swap(           \
+              MutableRaw<RepeatedField<TYPE> >(message2, field));            \
+          break;
+
+          SWAP_ARRAYS(INT32 , int32 );
+          SWAP_ARRAYS(INT64 , int64 );
+          SWAP_ARRAYS(UINT32, uint32);
+          SWAP_ARRAYS(UINT64, uint64);
+          SWAP_ARRAYS(FLOAT , float );
+          SWAP_ARRAYS(DOUBLE, double);
+          SWAP_ARRAYS(BOOL  , bool  );
+          SWAP_ARRAYS(ENUM  , int   );
+#undef SWAP_ARRAYS
+
+        case FieldDescriptor::CPPTYPE_STRING:
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          MutableRaw<RepeatedPtrFieldBase>(message1, field)->Swap(
+              MutableRaw<RepeatedPtrFieldBase>(message2, field));
+          break;
+
+        default:
+          GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+      }
     } else {
       switch (field->cpp_type()) {
 #define SWAP_VALUES(CPPTYPE, TYPE)                                           \
@@ -300,6 +363,7 @@ void GeneratedMessageReflection::Swap(
           swap(*MutableRaw<TYPE>(message1, field),                           \
                *MutableRaw<TYPE>(message2, field));                          \
           break;
+
           SWAP_VALUES(INT32 , int32 );
           SWAP_VALUES(INT64 , int64 );
           SWAP_VALUES(UINT32, uint32);
@@ -307,10 +371,15 @@ void GeneratedMessageReflection::Swap(
           SWAP_VALUES(FLOAT , float );
           SWAP_VALUES(DOUBLE, double);
           SWAP_VALUES(BOOL  , bool  );
-          SWAP_VALUES(ENUM  , int32 );
-          SWAP_VALUES(STRING, string*);
+          SWAP_VALUES(ENUM  , int   );
           SWAP_VALUES(MESSAGE, Message*);
-#undef SWAP_PRIMITIVE_VALUES
+#undef SWAP_VALUES
+
+        case FieldDescriptor::CPPTYPE_STRING:
+            swap(*MutableRaw<string*>(message1, field),
+                 *MutableRaw<string*>(message2, field));
+          break;
+
         default:
           GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
       }
@@ -346,7 +415,28 @@ int GeneratedMessageReflection::FieldSize(const Message& message,
   if (field->is_extension()) {
     return GetExtensionSet(message).ExtensionSize(field->number());
   } else {
-    return GetRaw<GenericRepeatedField>(message, field).GenericSize();
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+      case FieldDescriptor::CPPTYPE_##UPPERCASE :                             \
+        return GetRaw<RepeatedField<LOWERCASE> >(message, field).size()
+
+      HANDLE_TYPE( INT32,  int32);
+      HANDLE_TYPE( INT64,  int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE( FLOAT,  float);
+      HANDLE_TYPE(  BOOL,   bool);
+      HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+    }
+
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
   }
 }
 
@@ -401,7 +491,35 @@ void GeneratedMessageReflection::ClearField(
       }
     }
   } else {
-    MutableRaw<GenericRepeatedField>(message, field)->GenericClear();
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+      case FieldDescriptor::CPPTYPE_##UPPERCASE :                             \
+        MutableRaw<RepeatedField<LOWERCASE> >(message, field)->Clear();       \
+        break
+
+      HANDLE_TYPE( INT32,  int32);
+      HANDLE_TYPE( INT64,  int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE( FLOAT,  float);
+      HANDLE_TYPE(  BOOL,   bool);
+      HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING: {
+          MutableRaw<RepeatedPtrField<string> >(message, field)->Clear();
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        // We don't know which subclass of RepeatedPtrFieldBase the type is,
+        // so we use RepeatedPtrFieldBase directly.
+        MutableRaw<RepeatedPtrFieldBase>(message, field)
+            ->Clear<GenericTypeHandler<Message> >();
+        break;
+      }
+    }
   }
 }
 
@@ -414,7 +532,31 @@ void GeneratedMessageReflection::RemoveLast(
   if (field->is_extension()) {
     MutableExtensionSet(message)->RemoveLast(field->number());
   } else {
-    MutableRaw<GenericRepeatedField>(message, field)->GenericRemoveLast();
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+      case FieldDescriptor::CPPTYPE_##UPPERCASE :                             \
+        MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast();  \
+        break
+
+      HANDLE_TYPE( INT32,  int32);
+      HANDLE_TYPE( INT64,  int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE( FLOAT,  float);
+      HANDLE_TYPE(  BOOL,   bool);
+      HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+          MutableRaw<RepeatedPtrField<string> >(message, field)->RemoveLast();
+        break;
+
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        MutableRaw<RepeatedPtrFieldBase>(message, field)
+            ->RemoveLast<GenericTypeHandler<Message> >();
+        break;
+    }
   }
 }
 
@@ -427,11 +569,31 @@ void GeneratedMessageReflection::SwapElements(
   USAGE_CHECK_REPEATED(Swap);
 
   if (field->is_extension()) {
-    MutableExtensionSet(message)->SwapElements(
-                                      field->number(), index1, index2);
+    MutableExtensionSet(message)->SwapElements(field->number(), index1, index2);
   } else {
-    MutableRaw<GenericRepeatedField>(message, field)->GenericSwapElements(
-                                                            index1, index2);
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+      case FieldDescriptor::CPPTYPE_##UPPERCASE :                             \
+        MutableRaw<RepeatedField<LOWERCASE> >(message, field)                 \
+            ->SwapElements(index1, index2);                                   \
+        break
+
+      HANDLE_TYPE( INT32,  int32);
+      HANDLE_TYPE( INT64,  int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE( FLOAT,  float);
+      HANDLE_TYPE(  BOOL,   bool);
+      HANDLE_TYPE(  ENUM,    int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        MutableRaw<RepeatedPtrFieldBase>(message, field)
+            ->SwapElements(index1, index2);
+        break;
+    }
   }
 }
 
@@ -456,7 +618,7 @@ void GeneratedMessageReflection::ListFields(
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     if (field->is_repeated()) {
-      if (GetRaw<GenericRepeatedField>(message, field).GenericSize() > 0) {
+      if (FieldSize(message, field) > 0) {
         output->push_back(field);
       }
     } else {
@@ -597,7 +759,7 @@ string GeneratedMessageReflection::GetRepeatedString(
   if (field->is_extension()) {
     return GetExtensionSet(message).GetRepeatedString(field->number(), index);
   } else {
-    return GetRepeatedField<string>(message, field, index);
+    return GetRepeatedPtrField<string>(message, field, index);
   }
 }
 
@@ -608,7 +770,7 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference(
   if (field->is_extension()) {
     return GetExtensionSet(message).GetRepeatedString(field->number(), index);
   } else {
-    return GetRepeatedField<string>(message, field, index);
+    return GetRepeatedPtrField<string>(message, field, index);
   }
 }
 
@@ -621,7 +783,7 @@ void GeneratedMessageReflection::SetRepeatedString(
     MutableExtensionSet(message)->SetRepeatedString(
       field->number(), index, value);
   } else {
-    SetRepeatedField<string>(message, field, index, value);
+    *MutableRepeatedField<string>(message, field, index) = value;
   }
 }
 
@@ -634,7 +796,7 @@ void GeneratedMessageReflection::AddString(
     MutableExtensionSet(message)->AddString(field->number(),
                                             field->type(), value);
   } else {
-    AddField<string>(message, field, value);
+    *AddField<string>(message, field) = value;
   }
 }
 
@@ -725,9 +887,10 @@ const Message& GeneratedMessageReflection::GetMessage(
   USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
 
   if (field->is_extension()) {
-    return GetExtensionSet(message).GetMessage(field->number(),
-                                               field->message_type(),
-                                               message_factory_);
+    return static_cast<const Message&>(
+      GetExtensionSet(message).GetMessage(field->number(),
+                                          field->message_type(),
+                                          message_factory_));
   } else {
     const Message* result = GetRaw<const Message*>(message, field);
     if (result == NULL) {
@@ -742,10 +905,11 @@ Message* GeneratedMessageReflection::MutableMessage(
   USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
 
   if (field->is_extension()) {
-    return MutableExtensionSet(message)->MutableMessage(field->number(),
-                                                        field->type(),
-                                                        field->message_type(),
-                                                        message_factory_);
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableMessage(field->number(),
+                                                     field->type(),
+                                                     field->message_type(),
+                                                     message_factory_));
   } else {
     Message** result = MutableField<Message*>(message, field);
     if (*result == NULL) {
@@ -761,9 +925,11 @@ const Message& GeneratedMessageReflection::GetRepeatedMessage(
   USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
 
   if (field->is_extension()) {
-    return GetExtensionSet(message).GetRepeatedMessage(field->number(), index);
+    return static_cast<const Message&>(
+        GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
   } else {
-    return GetRepeatedField<Message>(message, field, index);
+    return GetRaw<RepeatedPtrFieldBase>(message, field)
+        .Get<GenericTypeHandler<Message> >(index);
   }
 }
 
@@ -772,10 +938,12 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage(
   USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE);
 
   if (field->is_extension()) {
-    return MutableExtensionSet(message)->MutableRepeatedMessage(
-      field->number(), index);
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableRepeatedMessage(
+          field->number(), index));
   } else {
-    return MutableRepeatedField<Message>(message, field, index);
+    return MutableRaw<RepeatedPtrFieldBase>(message, field)
+        ->Mutable<GenericTypeHandler<Message> >(index);
   }
 }
 
@@ -784,12 +952,29 @@ Message* GeneratedMessageReflection::AddMessage(
   USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE);
 
   if (field->is_extension()) {
-    return MutableExtensionSet(message)->AddMessage(field->number(),
-                                                    field->type(),
-                                                    field->message_type(),
-                                                    message_factory_);
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->AddMessage(field->number(),
+                                                 field->type(),
+                                                 field->message_type(),
+                                                 message_factory_));
   } else {
-    return AddField<Message>(message, field);
+    // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
+    // know how to allocate one.
+    RepeatedPtrFieldBase* repeated =
+      MutableRaw<RepeatedPtrFieldBase>(message, field);
+    Message* result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
+    if (result == NULL) {
+      // We must allocate a new object.
+      const Message* prototype;
+      if (repeated->size() == 0) {
+        prototype = message_factory_->GetPrototype(field->message_type());
+      } else {
+        prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
+      }
+      result = prototype->New();
+      repeated->AddAllocated<GenericTypeHandler<Message> >(result);
+    }
+    return result;
   }
 }
 
@@ -925,46 +1110,46 @@ inline Type* GeneratedMessageReflection::MutableField(
 }
 
 template <typename Type>
-inline const Type& GeneratedMessageReflection::GetRepeatedField(
+inline Type GeneratedMessageReflection::GetRepeatedField(
+    const Message& message, const FieldDescriptor* field, int index) const {
+  return GetRaw<RepeatedField<Type> >(message, field).Get(index);
+}
+
+template <typename Type>
+inline const Type& GeneratedMessageReflection::GetRepeatedPtrField(
     const Message& message, const FieldDescriptor* field, int index) const {
-  return *reinterpret_cast<const Type*>(
-    GetRaw<GenericRepeatedField>(message, field).GenericGet(index));
+  return GetRaw<RepeatedPtrField<Type> >(message, field).Get(index);
 }
 
 template <typename Type>
 inline void GeneratedMessageReflection::SetRepeatedField(
     Message* message, const FieldDescriptor* field,
-    int index, const Type& value) const {
-  GenericRepeatedField* repeated =
-    MutableRaw<GenericRepeatedField>(message, field);
-  *reinterpret_cast<Type*>(repeated->GenericMutable(index)) = value;
+    int index, Type value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Set(index, value);
 }
 
 template <typename Type>
 inline Type* GeneratedMessageReflection::MutableRepeatedField(
     Message* message, const FieldDescriptor* field, int index) const {
-  GenericRepeatedField* repeated =
-    MutableRaw<GenericRepeatedField>(message, field);
-  return reinterpret_cast<Type*>(repeated->GenericMutable(index));
+  RepeatedPtrField<Type>* repeated =
+    MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Mutable(index);
 }
 
 template <typename Type>
 inline void GeneratedMessageReflection::AddField(
-    Message* message, const FieldDescriptor* field, const Type& value) const {
-  GenericRepeatedField* repeated =
-    MutableRaw<GenericRepeatedField>(message, field);
-  *reinterpret_cast<Type*>(repeated->GenericAdd()) = value;
+    Message* message, const FieldDescriptor* field, Type value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Add(value);
 }
 
 template <typename Type>
 inline Type* GeneratedMessageReflection::AddField(
     Message* message, const FieldDescriptor* field) const {
-  GenericRepeatedField* repeated =
-    MutableRaw<GenericRepeatedField>(message, field);
-  return reinterpret_cast<Type*>(repeated->GenericAdd());
+  RepeatedPtrField<Type>* repeated =
+    MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Add();
 }
 
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google

+ 10 - 12
src/google/protobuf/generated_message_reflection.h

@@ -142,7 +142,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
   void ClearField(Message* message, const FieldDescriptor* field) const;
   void RemoveLast(Message* message, const FieldDescriptor* field) const;
   void Swap(Message* message1, Message* message2) const;
-  void SwapElements(Message* message, const FieldDescriptor* field, 
+  void SwapElements(Message* message, const FieldDescriptor* field,
             int index1, int index2) const;
   void ListFields(const Message& message,
                   vector<const FieldDescriptor*>* output) const;
@@ -314,20 +314,24 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
   inline Type* MutableField(Message* message,
                             const FieldDescriptor* field) const;
   template <typename Type>
-  inline const Type& GetRepeatedField(const Message& message,
-                                      const FieldDescriptor* field,
-                                      int index) const;
+  inline Type GetRepeatedField(const Message& message,
+                               const FieldDescriptor* field,
+                               int index) const;
+  template <typename Type>
+  inline const Type& GetRepeatedPtrField(const Message& message,
+                                         const FieldDescriptor* field,
+                                         int index) const;
   template <typename Type>
   inline void SetRepeatedField(Message* message,
                                const FieldDescriptor* field, int index,
-                               const Type& value) const;
+                               Type value) const;
   template <typename Type>
   inline Type* MutableRepeatedField(Message* message,
                                     const FieldDescriptor* field,
                                     int index) const;
   template <typename Type>
   inline void AddField(Message* message,
-                       const FieldDescriptor* field, const Type& value) const;
+                       const FieldDescriptor* field, Type value) const;
   template <typename Type>
   inline Type* AddField(Message* message,
                         const FieldDescriptor* field) const;
@@ -388,11 +392,6 @@ inline To dynamic_cast_if_available(From from) {
 #endif
 }
 
-// Compute the space used by a string, not including sizeof(string) itself.
-// This is slightly complicated because small strings store their data within
-// the string object but large strings do not.
-LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
-
 // Helper for EnumType_Parse functions: try to parse the string 'name' as an
 // enum name of the given type, returning true and filling in value on success,
 // or returning false and leaving value unchanged on failure.
@@ -415,7 +414,6 @@ bool ParseNamedEnum(const EnumDescriptor* descriptor,
 // descriptor.h.
 LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
 
-
 }  // namespace internal
 }  // namespace protobuf
 

+ 44 - 0
src/google/protobuf/generated_message_util.cc

@@ -0,0 +1,44 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/generated_message_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google

+ 65 - 0
src/google/protobuf/generated_message_util.h

@@ -0,0 +1,65 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains miscellaneous helper code used by generated code --
+// including lite types -- but which should not be used directly by users.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Annotation for the compiler to emit a deprecation message if a field marked
+// with option 'deprecated=true' is used in the code.
+//
+// For internal use in the pb.cc files, deprecation warnings are suppressed
+// there.
+#undef DEPRECATED_PROTOBUF_FIELD
+#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
+#  define DEPRECATED_PROTOBUF_FIELD GOOGLE_ATTRIBUTE_DEPRECATED
+#else
+#  define DEPRECATED_PROTOBUF_FIELD
+#endif
+
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__

+ 46 - 50
src/google/protobuf/io/coded_stream.cc

@@ -80,18 +80,49 @@ CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
     total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
     recursion_depth_(0),
     recursion_limit_(kDefaultRecursionLimit) {
+  // Eagerly Refresh() so buffer space is immediately available.
+  Refresh();
+}
+
+CodedInputStream::CodedInputStream(const uint8* buffer, int size)
+  : input_(NULL),
+    buffer_(buffer),
+    buffer_size_(size),
+    total_bytes_read_(size),
+    overflow_bytes_(0),
+    last_tag_(0),
+    legitimate_message_end_(false),
+    aliasing_enabled_(false),
+    current_limit_(size),
+    buffer_size_after_limit_(0),
+    total_bytes_limit_(kDefaultTotalBytesLimit),
+    total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
+    recursion_depth_(0),
+    recursion_limit_(kDefaultRecursionLimit) {
+  // Note that setting current_limit_ == size is important to prevent some
+  // code paths from trying to access input_ and segfaulting.
 }
 
 CodedInputStream::~CodedInputStream() {
+  if (input_ != NULL) {
+    BackUpInputToCurrentPosition();
+  }
+}
+
+
+void CodedInputStream::BackUpInputToCurrentPosition() {
   int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_;
   if (backup_bytes > 0) {
-    // We still have bytes left over from the last buffer.  Back up over
-    // them.
     input_->BackUp(backup_bytes);
+
+    // total_bytes_read_ doesn't include overflow_bytes_.
+    total_bytes_read_ -= buffer_size_ + buffer_size_after_limit_;
+    buffer_size_ = 0;
+    buffer_size_after_limit_ = 0;
+    overflow_bytes_ = 0;
   }
 }
 
-
 inline void CodedInputStream::RecomputeBufferLimits() {
   buffer_size_ += buffer_size_after_limit_;
   int closest_limit = min(current_limit_, total_bytes_limit_);
@@ -193,8 +224,10 @@ bool CodedInputStream::Skip(int count) {
   int bytes_until_limit = closest_limit - total_bytes_read_;
   if (bytes_until_limit < count) {
     // We hit the limit.  Skip up to it then fail.
-    total_bytes_read_ = closest_limit;
-    input_->Skip(bytes_until_limit);
+    if (bytes_until_limit > 0) {
+      total_bytes_read_ = closest_limit;
+      input_->Skip(bytes_until_limit);
+    }
     return false;
   }
 
@@ -216,6 +249,7 @@ bool CodedInputStream::ReadRaw(void* buffer, int size) {
     memcpy(buffer, buffer_, buffer_size_);
     buffer = reinterpret_cast<uint8*>(buffer) + buffer_size_;
     size -= buffer_size_;
+    Advance(buffer_size_);
     if (!Refresh()) return false;
   }
 
@@ -247,6 +281,7 @@ bool CodedInputStream::ReadString(string* buffer, int size) {
       buffer->append(reinterpret_cast<const char*>(buffer_), buffer_size_);
     }
     size -= buffer_size_;
+    Advance(buffer_size_);
     if (!Refresh()) return false;
   }
 
@@ -441,11 +476,11 @@ bool CodedInputStream::ReadVarint64(uint64* value) {
 }
 
 bool CodedInputStream::Refresh() {
-  if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0) {
-    // We've hit a limit.  Stop.
-    buffer_ += buffer_size_;
-    buffer_size_ = 0;
+  GOOGLE_DCHECK_EQ(buffer_size_, 0);
 
+  if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
+      total_bytes_read_ == current_limit_) {
+    // We've hit a limit.  Stop.
     int current_position = total_bytes_read_ - buffer_size_after_limit_;
 
     if (current_position >= total_bytes_limit_ &&
@@ -570,10 +605,7 @@ void CodedOutputStream::WriteLittleEndian32(uint32 value) {
   bool use_fast = buffer_size_ >= sizeof(value);
   uint8* ptr = use_fast ? buffer_ : bytes;
 
-  ptr[0] = static_cast<uint8>(value      );
-  ptr[1] = static_cast<uint8>(value >>  8);
-  ptr[2] = static_cast<uint8>(value >> 16);
-  ptr[3] = static_cast<uint8>(value >> 24);
+  WriteLittleEndian32ToArray(value, ptr);
 
   if (use_fast) {
     Advance(sizeof(value));
@@ -582,32 +614,13 @@ void CodedOutputStream::WriteLittleEndian32(uint32 value) {
   }
 }
 
-uint8* CodedOutputStream::WriteLittleEndian32ToArray(
-    uint32 value, uint8* target) {
-  target[0] = static_cast<uint8>(value      );
-  target[1] = static_cast<uint8>(value >>  8);
-  target[2] = static_cast<uint8>(value >> 16);
-  target[3] = static_cast<uint8>(value >> 24);
-  return target + sizeof(value);
-}
-
 void CodedOutputStream::WriteLittleEndian64(uint64 value) {
   uint8 bytes[sizeof(value)];
 
-  uint32 part0 = static_cast<uint32>(value);
-  uint32 part1 = static_cast<uint32>(value >> 32);
-
   bool use_fast = buffer_size_ >= sizeof(value);
   uint8* ptr = use_fast ? buffer_ : bytes;
 
-  ptr[0] = static_cast<uint8>(part0      );
-  ptr[1] = static_cast<uint8>(part0 >>  8);
-  ptr[2] = static_cast<uint8>(part0 >> 16);
-  ptr[3] = static_cast<uint8>(part0 >> 24);
-  ptr[4] = static_cast<uint8>(part1      );
-  ptr[5] = static_cast<uint8>(part1 >>  8);
-  ptr[6] = static_cast<uint8>(part1 >> 16);
-  ptr[7] = static_cast<uint8>(part1 >> 24);
+  WriteLittleEndian64ToArray(value, ptr);
 
   if (use_fast) {
     Advance(sizeof(value));
@@ -616,23 +629,6 @@ void CodedOutputStream::WriteLittleEndian64(uint64 value) {
   }
 }
 
-uint8* CodedOutputStream::WriteLittleEndian64ToArray(
-    uint64 value, uint8* target) {
-  uint32 part0 = static_cast<uint32>(value);
-  uint32 part1 = static_cast<uint32>(value >> 32);
-
-  target[0] = static_cast<uint8>(part0      );
-  target[1] = static_cast<uint8>(part0 >>  8);
-  target[2] = static_cast<uint8>(part0 >> 16);
-  target[3] = static_cast<uint8>(part0 >> 24);
-  target[4] = static_cast<uint8>(part1      );
-  target[5] = static_cast<uint8>(part1 >>  8);
-  target[6] = static_cast<uint8>(part1 >> 16);
-  target[7] = static_cast<uint8>(part1 >> 24);
-
-  return target + sizeof(value);
-}
-
 inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
     uint32 value, uint8* target) {
   target[0] = static_cast<uint8>(value | 0x80);

+ 46 - 0
src/google/protobuf/io/coded_stream.h

@@ -110,6 +110,9 @@
 #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 
 #include <string>
+#ifndef _MSC_VER
+#include <sys/param.h>
+#endif  // !_MSC_VER
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -137,6 +140,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
   // Create a CodedInputStream that reads from the given ZeroCopyInputStream.
   explicit CodedInputStream(ZeroCopyInputStream* input);
 
+  // Create a CodedInputStream that reads from the given flat array.  This is
+  // faster than using an ArrayInputStream.  PushLimit(size) is implied by
+  // this constructor.
+  explicit CodedInputStream(const uint8* buffer, int size);
+
   // Destroy the CodedInputStream and position the underlying
   // ZeroCopyInputStream at the first unread byte.  If an error occurred while
   // reading (causing a method to return false), then the exact position of
@@ -360,6 +368,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
   // Advance the buffer by a given number of bytes.
   void Advance(int amount);
 
+  // Back up input_ to the current buffer position.
+  void BackUpInputToCurrentPosition();
+
   // Recomputes the value of buffer_size_after_limit_.  Must be called after
   // current_limit_ or total_bytes_limit_ changes.
   void RecomputeBufferLimits();
@@ -664,6 +675,41 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray(
   }
 }
 
+inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value,
+                                                            uint8* target) {
+#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \
+    defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
+  memcpy(target, &value, sizeof(value));
+#else
+  target[0] = static_cast<uint8>(value      );
+  target[1] = static_cast<uint8>(value >>  8);
+  target[2] = static_cast<uint8>(value >> 16);
+  target[3] = static_cast<uint8>(value >> 24);
+#endif
+  return target + sizeof(value);
+}
+
+inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
+                                                            uint8* target) {
+#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \
+    defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
+  memcpy(target, &value, sizeof(value));
+#else
+  uint32 part0 = static_cast<uint32>(value);
+  uint32 part1 = static_cast<uint32>(value >> 32);
+
+  target[0] = static_cast<uint8>(part0      );
+  target[1] = static_cast<uint8>(part0 >>  8);
+  target[2] = static_cast<uint8>(part0 >> 16);
+  target[3] = static_cast<uint8>(part0 >> 24);
+  target[4] = static_cast<uint8>(part1      );
+  target[5] = static_cast<uint8>(part1 >>  8);
+  target[6] = static_cast<uint8>(part1 >> 16);
+  target[7] = static_cast<uint8>(part1 >> 24);
+#endif
+  return target + sizeof(value);
+}
+
 inline void CodedOutputStream::WriteTag(uint32 value) {
   WriteVarint32(value);
 }

+ 3 - 4
src/google/protobuf/io/gzip_stream.cc

@@ -1,5 +1,5 @@
 // Protocol Buffers - Google's data interchange format
-// Copyright 2009 Google Inc.  All rights reserved.
+// Copyright 2008 Google Inc.  All rights reserved.
 // http://code.google.com/p/protobuf/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Author: brianolson@google.com (Brian Olson)
-//  Based on original Protocol Buffers design by
-//  Sanjay Ghemawat, Jeff Dean, and others.
 //
 // This file contains the implementation of classes GzipInputStream and
 // GzipOutputStream.
@@ -39,6 +37,7 @@
 
 #if HAVE_ZLIB
 #include <google/protobuf/io/gzip_stream.h>
+
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -291,6 +290,6 @@ bool GzipOutputStream::Close() {
 
 }  // namespace io
 }  // namespace protobuf
-}  // namespace google
 
 #endif  // HAVE_ZLIB
+}  // namespace google

+ 2 - 4
src/google/protobuf/io/gzip_stream.h

@@ -1,5 +1,5 @@
 // Protocol Buffers - Google's data interchange format
-// Copyright 2009 Google Inc.  All rights reserved.
+// Copyright 2008 Google Inc.  All rights reserved.
 // http://code.google.com/p/protobuf/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Author: brianolson@google.com (Brian Olson)
-//  Based on original Protocol Buffers design by
-//  Sanjay Ghemawat, Jeff Dean, and others.
 //
 // This file contains the definition for classes GzipInputStream and
 // GzipOutputStream.
@@ -173,6 +171,6 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
 
 }  // namespace io
 }  // namespace protobuf
-}  // namespace google
 
+}  // namespace google
 #endif  // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__

+ 1 - 1
src/google/protobuf/io/tokenizer.cc

@@ -571,7 +571,7 @@ bool Tokenizer::ParseInteger(const string& text, uint64 max_value,
   const char* ptr = text.c_str();
   int base = 10;
   if (ptr[0] == '0') {
-    if (ptr[1] == 'x') {
+    if (ptr[1] == 'x' || ptr[1] == 'X') {
       // This is hex.
       base = 16;
       ptr += 2;

+ 1 - 0
src/google/protobuf/io/tokenizer_unittest.cc

@@ -487,6 +487,7 @@ TEST_F(TokenizerTest, ParseInteger) {
   EXPECT_EQ(0xabcdef12u, ParseInteger("0xABCDEF12"));
   EXPECT_EQ(kuint64max, ParseInteger("0xFFFFFFFFFFFFFFFF"));
   EXPECT_EQ(01234567, ParseInteger("01234567"));
+  EXPECT_EQ(0X123, ParseInteger("0X123"));
 
   // Test invalid integers that may still be tokenized as integers.
   EXPECT_EQ(0, ParseInteger("0x"));

+ 0 - 345
src/google/protobuf/io/zero_copy_stream_impl.cc

@@ -60,7 +60,6 @@ namespace io {
 
 namespace {
 
-
 // EINTR sucks.
 int close_no_eintr(int fd) {
   int result;
@@ -70,352 +69,8 @@ int close_no_eintr(int fd) {
   return result;
 }
 
-// Default block size for Copying{In,Out}putStreamAdaptor.
-static const int kDefaultBlockSize = 8192;
-
 }  // namespace
 
-// ===================================================================
-
-ArrayInputStream::ArrayInputStream(const void* data, int size,
-                                   int block_size)
-  : data_(reinterpret_cast<const uint8*>(data)),
-    size_(size),
-    block_size_(block_size > 0 ? block_size : size),
-    position_(0),
-    last_returned_size_(0) {
-}
-
-ArrayInputStream::~ArrayInputStream() {
-}
-
-bool ArrayInputStream::Next(const void** data, int* size) {
-  if (position_ < size_) {
-    last_returned_size_ = min(block_size_, size_ - position_);
-    *data = data_ + position_;
-    *size = last_returned_size_;
-    position_ += last_returned_size_;
-    return true;
-  } else {
-    // We're at the end of the array.
-    last_returned_size_ = 0;   // Don't let caller back up.
-    return false;
-  }
-}
-
-void ArrayInputStream::BackUp(int count) {
-  GOOGLE_CHECK_GT(last_returned_size_, 0)
-      << "BackUp() can only be called after a successful Next().";
-  GOOGLE_CHECK_LE(count, last_returned_size_);
-  GOOGLE_CHECK_GE(count, 0);
-  position_ -= count;
-  last_returned_size_ = 0;  // Don't let caller back up further.
-}
-
-bool ArrayInputStream::Skip(int count) {
-  GOOGLE_CHECK_GE(count, 0);
-  last_returned_size_ = 0;   // Don't let caller back up.
-  if (count > size_ - position_) {
-    position_ = size_;
-    return false;
-  } else {
-    position_ += count;
-    return true;
-  }
-}
-
-int64 ArrayInputStream::ByteCount() const {
-  return position_;
-}
-
-
-// ===================================================================
-
-ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
-  : data_(reinterpret_cast<uint8*>(data)),
-    size_(size),
-    block_size_(block_size > 0 ? block_size : size),
-    position_(0),
-    last_returned_size_(0) {
-}
-
-ArrayOutputStream::~ArrayOutputStream() {
-}
-
-bool ArrayOutputStream::Next(void** data, int* size) {
-  if (position_ < size_) {
-    last_returned_size_ = min(block_size_, size_ - position_);
-    *data = data_ + position_;
-    *size = last_returned_size_;
-    position_ += last_returned_size_;
-    return true;
-  } else {
-    // We're at the end of the array.
-    last_returned_size_ = 0;   // Don't let caller back up.
-    return false;
-  }
-}
-
-void ArrayOutputStream::BackUp(int count) {
-  GOOGLE_CHECK_GT(last_returned_size_, 0)
-      << "BackUp() can only be called after a successful Next().";
-  GOOGLE_CHECK_LE(count, last_returned_size_);
-  GOOGLE_CHECK_GE(count, 0);
-  position_ -= count;
-  last_returned_size_ = 0;  // Don't let caller back up further.
-}
-
-int64 ArrayOutputStream::ByteCount() const {
-  return position_;
-}
-
-// ===================================================================
-
-StringOutputStream::StringOutputStream(string* target)
-  : target_(target) {
-}
-
-StringOutputStream::~StringOutputStream() {
-}
-
-bool StringOutputStream::Next(void** data, int* size) {
-  int old_size = target_->size();
-
-  // Grow the string.
-  if (old_size < target_->capacity()) {
-    // Resize the string to match its capacity, since we can get away
-    // without a memory allocation this way.
-    STLStringResizeUninitialized(target_, target_->capacity());
-  } else {
-    // Size has reached capacity, so double the size.  Also make sure
-    // that the new size is at least kMinimumSize.
-    STLStringResizeUninitialized(
-      target_,
-      max(old_size * 2,
-          kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
-  }
-
-  *data = string_as_array(target_) + old_size;
-  *size = target_->size() - old_size;
-  return true;
-}
-
-void StringOutputStream::BackUp(int count) {
-  GOOGLE_CHECK_GE(count, 0);
-  GOOGLE_CHECK_LE(count, target_->size());
-  target_->resize(target_->size() - count);
-}
-
-int64 StringOutputStream::ByteCount() const {
-  return target_->size();
-}
-
-// ===================================================================
-
-
-// ===================================================================
-
-CopyingInputStream::~CopyingInputStream() {}
-
-int CopyingInputStream::Skip(int count) {
-  char junk[4096];
-  int skipped = 0;
-  while (skipped < count) {
-    int bytes = Read(junk, min(count - skipped,
-                               implicit_cast<int>(sizeof(junk))));
-    if (bytes <= 0) {
-      // EOF or read error.
-      return skipped;
-    }
-    skipped += bytes;
-  }
-  return skipped;
-}
-
-CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
-    CopyingInputStream* copying_stream, int block_size)
-  : copying_stream_(copying_stream),
-    owns_copying_stream_(false),
-    failed_(false),
-    position_(0),
-    buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
-    buffer_used_(0),
-    backup_bytes_(0) {
-}
-
-CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
-  if (owns_copying_stream_) {
-    delete copying_stream_;
-  }
-}
-
-bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
-  if (failed_) {
-    // Already failed on a previous read.
-    return false;
-  }
-
-  AllocateBufferIfNeeded();
-
-  if (backup_bytes_ > 0) {
-    // We have data left over from a previous BackUp(), so just return that.
-    *data = buffer_.get() + buffer_used_ - backup_bytes_;
-    *size = backup_bytes_;
-    backup_bytes_ = 0;
-    return true;
-  }
-
-  // Read new data into the buffer.
-  buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
-  if (buffer_used_ <= 0) {
-    // EOF or read error.  We don't need the buffer anymore.
-    if (buffer_used_ < 0) {
-      // Read error (not EOF).
-      failed_ = true;
-    }
-    FreeBuffer();
-    return false;
-  }
-  position_ += buffer_used_;
-
-  *size = buffer_used_;
-  *data = buffer_.get();
-  return true;
-}
-
-void CopyingInputStreamAdaptor::BackUp(int count) {
-  GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
-    << " BackUp() can only be called after Next().";
-  GOOGLE_CHECK_LE(count, buffer_used_)
-    << " Can't back up over more bytes than were returned by the last call"
-       " to Next().";
-  GOOGLE_CHECK_GE(count, 0)
-    << " Parameter to BackUp() can't be negative.";
-
-  backup_bytes_ = count;
-}
-
-bool CopyingInputStreamAdaptor::Skip(int count) {
-  GOOGLE_CHECK_GE(count, 0);
-
-  if (failed_) {
-    // Already failed on a previous read.
-    return false;
-  }
-
-  // First skip any bytes left over from a previous BackUp().
-  if (backup_bytes_ >= count) {
-    // We have more data left over than we're trying to skip.  Just chop it.
-    backup_bytes_ -= count;
-    return true;
-  }
-
-  count -= backup_bytes_;
-  backup_bytes_ = 0;
-
-  int skipped = copying_stream_->Skip(count);
-  position_ += skipped;
-  return skipped == count;
-}
-
-int64 CopyingInputStreamAdaptor::ByteCount() const {
-  return position_ - backup_bytes_;
-}
-
-void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
-  if (buffer_.get() == NULL) {
-    buffer_.reset(new uint8[buffer_size_]);
-  }
-}
-
-void CopyingInputStreamAdaptor::FreeBuffer() {
-  GOOGLE_CHECK_EQ(backup_bytes_, 0);
-  buffer_used_ = 0;
-  buffer_.reset();
-}
-
-// ===================================================================
-
-CopyingOutputStream::~CopyingOutputStream() {}
-
-CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
-    CopyingOutputStream* copying_stream, int block_size)
-  : copying_stream_(copying_stream),
-    owns_copying_stream_(false),
-    failed_(false),
-    position_(0),
-    buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
-    buffer_used_(0) {
-}
-
-CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
-  WriteBuffer();
-  if (owns_copying_stream_) {
-    delete copying_stream_;
-  }
-}
-
-bool CopyingOutputStreamAdaptor::Flush() {
-  return WriteBuffer();
-}
-
-bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
-  if (buffer_used_ == buffer_size_) {
-    if (!WriteBuffer()) return false;
-  }
-
-  AllocateBufferIfNeeded();
-
-  *data = buffer_.get() + buffer_used_;
-  *size = buffer_size_ - buffer_used_;
-  buffer_used_ = buffer_size_;
-  return true;
-}
-
-void CopyingOutputStreamAdaptor::BackUp(int count) {
-  GOOGLE_CHECK_GE(count, 0);
-  GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
-    << " BackUp() can only be called after Next().";
-  GOOGLE_CHECK_LE(count, buffer_used_)
-    << " Can't back up over more bytes than were returned by the last call"
-       " to Next().";
-
-  buffer_used_ -= count;
-}
-
-int64 CopyingOutputStreamAdaptor::ByteCount() const {
-  return position_ + buffer_used_;
-}
-
-bool CopyingOutputStreamAdaptor::WriteBuffer() {
-  if (failed_) {
-    // Already failed on a previous write.
-    return false;
-  }
-
-  if (buffer_used_ == 0) return true;
-
-  if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
-    position_ += buffer_used_;
-    buffer_used_ = 0;
-    return true;
-  } else {
-    failed_ = true;
-    FreeBuffer();
-    return false;
-  }
-}
-
-void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
-  if (buffer_ == NULL) {
-    buffer_.reset(new uint8[buffer_size_]);
-  }
-}
-
-void CopyingOutputStreamAdaptor::FreeBuffer() {
-  buffer_used_ = 0;
-  buffer_.reset();
-}
 
 // ===================================================================
 

Некоторые файлы не были показаны из-за большого количества измененных файлов