From fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Fri, 18 Dec 2009 02:11:36 +0000 Subject: Massive roll-up of changes. See CHANGES.txt. --- CHANGES.txt | 46 + Makefile.am | 6 - autogen.sh | 10 + generate_descriptor_proto.sh | 4 +- java/pom.xml | 1 + .../java/com/google/protobuf/AbstractMessage.java | 35 +- .../com/google/protobuf/AbstractMessageLite.java | 28 +- .../main/java/com/google/protobuf/ByteString.java | 18 + .../java/com/google/protobuf/CodedInputStream.java | 27 +- .../main/java/com/google/protobuf/Descriptors.java | 118 +- .../com/google/protobuf/ExtensionRegistry.java | 5 + .../java/com/google/protobuf/GeneratedMessage.java | 4 + .../com/google/protobuf/GeneratedMessageLite.java | 31 +- .../src/main/java/com/google/protobuf/Message.java | 4 +- .../main/java/com/google/protobuf/MessageLite.java | 8 +- .../main/java/com/google/protobuf/TextFormat.java | 2 +- .../java/com/google/protobuf/UnknownFieldSet.java | 20 +- .../main/java/com/google/protobuf/WireFormat.java | 18 +- .../com/google/protobuf/AbstractMessageTest.java | 38 + .../com/google/protobuf/CodedInputStreamTest.java | 14 + .../java/com/google/protobuf/DescriptorsTest.java | 51 + .../com/google/protobuf/GeneratedMessageTest.java | 35 +- .../test/java/com/google/protobuf/ServiceTest.java | 47 + .../test/java/com/google/protobuf/TestUtil.java | 92 ++ .../java/com/google/protobuf/TextFormatTest.java | 22 +- .../java/com/google/protobuf/WireFormatTest.java | 3 + python/google/protobuf/descriptor.py | 211 ++- python/google/protobuf/internal/containers.py | 69 +- python/google/protobuf/internal/decoder.py | 770 +++++++--- python/google/protobuf/internal/decoder_test.py | 256 ---- python/google/protobuf/internal/descriptor_test.py | 227 ++- python/google/protobuf/internal/encoder.py | 888 ++++++++---- python/google/protobuf/internal/encoder_test.py | 286 ---- python/google/protobuf/internal/generator_test.py | 107 +- python/google/protobuf/internal/input_stream.py | 338 ----- .../google/protobuf/internal/input_stream_test.py | 314 ----- .../google/protobuf/internal/message_listener.py | 41 +- python/google/protobuf/internal/message_test.py | 42 +- python/google/protobuf/internal/output_stream.py | 125 -- .../google/protobuf/internal/output_stream_test.py | 178 --- python/google/protobuf/internal/reflection_test.py | 354 ++++- python/google/protobuf/internal/test_util.py | 467 +++--- .../google/protobuf/internal/text_format_test.py | 25 +- python/google/protobuf/internal/type_checkers.py | 127 +- python/google/protobuf/internal/wire_format.py | 27 +- python/google/protobuf/message.py | 11 +- python/google/protobuf/reflection.py | 1487 +++++++------------- python/google/protobuf/text_format.py | 5 + python/setup.py | 11 +- src/Makefile.am | 29 +- src/google/protobuf/compiler/code_generator.cc | 9 +- src/google/protobuf/compiler/code_generator.h | 9 +- .../protobuf/compiler/command_line_interface.cc | 468 +++++- .../protobuf/compiler/command_line_interface.h | 65 +- .../compiler/command_line_interface_unittest.cc | 576 ++++---- .../compiler/cpp/cpp_bootstrap_unittest.cc | 11 +- src/google/protobuf/compiler/cpp/cpp_enum.cc | 14 +- src/google/protobuf/compiler/cpp/cpp_enum_field.cc | 71 +- src/google/protobuf/compiler/cpp/cpp_enum_field.h | 1 + src/google/protobuf/compiler/cpp/cpp_extension.cc | 21 +- src/google/protobuf/compiler/cpp/cpp_field.cc | 29 +- src/google/protobuf/compiler/cpp/cpp_field.h | 6 + src/google/protobuf/compiler/cpp/cpp_file.cc | 59 +- src/google/protobuf/compiler/cpp/cpp_helpers.cc | 53 +- src/google/protobuf/compiler/cpp/cpp_helpers.h | 24 +- src/google/protobuf/compiler/cpp/cpp_message.cc | 99 +- src/google/protobuf/compiler/cpp/cpp_message.h | 1 + .../protobuf/compiler/cpp/cpp_message_field.cc | 36 +- .../protobuf/compiler/cpp/cpp_primitive_field.cc | 78 +- .../protobuf/compiler/cpp/cpp_primitive_field.h | 1 + .../protobuf/compiler/cpp/cpp_string_field.cc | 35 +- src/google/protobuf/compiler/cpp/cpp_unittest.cc | 73 +- src/google/protobuf/compiler/java/java_enum.cc | 5 + .../protobuf/compiler/java/java_enum_field.cc | 46 +- .../protobuf/compiler/java/java_enum_field.h | 3 + .../protobuf/compiler/java/java_extension.cc | 3 +- src/google/protobuf/compiler/java/java_field.cc | 10 + src/google/protobuf/compiler/java/java_field.h | 2 + src/google/protobuf/compiler/java/java_file.cc | 40 +- src/google/protobuf/compiler/java/java_file.h | 5 + .../protobuf/compiler/java/java_generator.cc | 1 + src/google/protobuf/compiler/java/java_helpers.cc | 43 +- src/google/protobuf/compiler/java/java_helpers.h | 18 +- src/google/protobuf/compiler/java/java_message.cc | 83 +- .../protobuf/compiler/java/java_message_field.cc | 18 +- .../protobuf/compiler/java/java_message_field.h | 2 + .../protobuf/compiler/java/java_primitive_field.cc | 46 +- .../protobuf/compiler/java/java_primitive_field.h | 3 + src/google/protobuf/compiler/main.cc | 1 + src/google/protobuf/compiler/parser.cc | 11 +- src/google/protobuf/compiler/parser_unittest.cc | 6 + .../protobuf/compiler/python/python_generator.cc | 227 ++- .../protobuf/compiler/python/python_generator.h | 16 +- src/google/protobuf/descriptor.cc | 20 +- src/google/protobuf/descriptor.h | 23 +- src/google/protobuf/descriptor.pb.cc | 1327 ++++++++++------- src/google/protobuf/descriptor.pb.h | 637 +++++---- src/google/protobuf/descriptor.proto | 22 +- src/google/protobuf/descriptor_database.cc | 30 + src/google/protobuf/descriptor_database.h | 4 + .../protobuf/descriptor_database_unittest.cc | 34 + src/google/protobuf/descriptor_unittest.cc | 3 + src/google/protobuf/dynamic_message.cc | 80 +- src/google/protobuf/dynamic_message.h | 27 +- src/google/protobuf/extension_set.cc | 304 ++-- src/google/protobuf/extension_set.h | 202 ++- src/google/protobuf/extension_set_heavy.cc | 257 +++- src/google/protobuf/extension_set_unittest.cc | 159 +++ .../protobuf/generated_message_reflection.cc | 194 ++- src/google/protobuf/generated_message_reflection.h | 17 +- src/google/protobuf/generated_message_util.cc | 9 + src/google/protobuf/generated_message_util.h | 18 +- src/google/protobuf/io/coded_stream.cc | 379 +++-- src/google/protobuf/io/coded_stream.h | 347 ++++- src/google/protobuf/io/coded_stream_unittest.cc | 88 +- src/google/protobuf/io/gzip_stream.cc | 2 +- src/google/protobuf/io/printer.cc | 25 +- src/google/protobuf/io/printer.h | 19 +- src/google/protobuf/io/printer_unittest.cc | 69 +- src/google/protobuf/io/tokenizer.cc | 2 +- src/google/protobuf/io/tokenizer.h | 5 + src/google/protobuf/io/tokenizer_unittest.cc | 6 + src/google/protobuf/io/zero_copy_stream_impl.h | 9 +- .../protobuf/io/zero_copy_stream_unittest.cc | 3 +- src/google/protobuf/message.cc | 4 +- src/google/protobuf/message.h | 28 +- src/google/protobuf/message_lite.cc | 59 +- src/google/protobuf/repeated_field.cc | 12 + src/google/protobuf/repeated_field.h | 273 +++- src/google/protobuf/repeated_field_unittest.cc | 214 +++ src/google/protobuf/stubs/common.h | 31 +- src/google/protobuf/stubs/strutil.cc | 34 +- src/google/protobuf/stubs/strutil.h | 8 + src/google/protobuf/test_util.cc | 88 +- src/google/protobuf/test_util.h | 3 + src/google/protobuf/testing/file.cc | 13 +- src/google/protobuf/text_format.cc | 156 +- src/google/protobuf/text_format.h | 35 + src/google/protobuf/text_format_unittest.cc | 83 +- src/google/protobuf/unittest.proto | 93 +- .../protobuf/unittest_enormous_descriptor.proto | 1 + src/google/protobuf/unknown_field_set.cc | 12 +- src/google/protobuf/unknown_field_set.h | 10 +- src/google/protobuf/wire_format.cc | 185 ++- src/google/protobuf/wire_format_lite.cc | 175 ++- src/google/protobuf/wire_format_lite.h | 156 +- src/google/protobuf/wire_format_lite_inl.h | 366 +++-- src/google/protobuf/wire_format_unittest.cc | 71 + vsprojects/libprotobuf-lite.vcproj | 540 +++---- vsprojects/libprotobuf.vcproj | 860 +++++------ vsprojects/lite-test.vcproj | 546 +++---- vsprojects/protobuf.sln | 160 +-- vsprojects/tests.vcproj | 1146 +++++++-------- 153 files changed, 11619 insertions(+), 7474 deletions(-) delete mode 100755 python/google/protobuf/internal/decoder_test.py delete mode 100755 python/google/protobuf/internal/encoder_test.py delete mode 100755 python/google/protobuf/internal/input_stream.py delete mode 100755 python/google/protobuf/internal/input_stream_test.py delete mode 100755 python/google/protobuf/internal/output_stream.py delete mode 100755 python/google/protobuf/internal/output_stream_test.py diff --git a/CHANGES.txt b/CHANGES.txt index 34ba7367..02ce55cd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,49 @@ +2009-12-17 version 2.3.0: + + General + * Parsers for repeated numeric fields now always accept both packed and + unpacked input. The [packed=true] option only affects serializers. + Therefore, it is possible to switch a field to packed format without + breaking backwards-compatibility -- as long as all parties are using + protobuf 2.3.0 or above, at least. + * The generic RPC service code generated by the C++, Java, and Python + generators can be disabled via file options: + option cc_generic_services = false; + option java_generic_services = false; + option py_generic_services = false; + This allows plugins to generate alternative code, possibly specific to some + particular RPC implementation. + + protoc + * Now supports a plugin system for code generators. Plugins can generate + code for new languages or inject additional code into the output of other + code generators. Plugins are just binaries which accept a protocol buffer + on stdin and write a protocol buffer to stdout, so they may be written in + any language. See src/google/protobuf/compiler/plugin.proto. + * inf, -inf, and nan can now be used as default values for float and double + fields. + + C++ + * Various speed and code size optimizations. + * DynamicMessageFactory is now fully thread-safe. + * Message::Utf8DebugString() method is like DebugString() but avoids escaping + UTF-8 bytes. + * Compiled-in message types can now contain dynamic extensions, through use + of CodedInputStream::SetExtensionRegistry(). + + Java + * parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return + false/null instead of throwing an exception. + * Fixed some initialization ordering bugs. + * Fixes for OpenJDK 7. + + Python + * 10-25 times faster than 2.2.0, still pure-Python. + * Calling a mutating method on a sub-message always instantiates the message + in its parent even if the mutating method doesn't actually mutate anything + (e.g. parsing from an empty string). + * Expanded descriptors a bit. + 2009-08-11 version 2.2.0: C++ diff --git a/Makefile.am b/Makefile.am index c311fe02..fbd36c1a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -114,18 +114,12 @@ EXTRA_DIST = \ python/google/protobuf/internal/generator_test.py \ python/google/protobuf/internal/containers.py \ python/google/protobuf/internal/decoder.py \ - python/google/protobuf/internal/decoder_test.py \ python/google/protobuf/internal/descriptor_test.py \ python/google/protobuf/internal/encoder.py \ - python/google/protobuf/internal/encoder_test.py \ - python/google/protobuf/internal/input_stream.py \ - python/google/protobuf/internal/input_stream_test.py \ python/google/protobuf/internal/message_listener.py \ python/google/protobuf/internal/message_test.py \ python/google/protobuf/internal/more_extensions.proto \ python/google/protobuf/internal/more_messages.proto \ - python/google/protobuf/internal/output_stream.py \ - python/google/protobuf/internal/output_stream_test.py \ python/google/protobuf/internal/reflection_test.py \ python/google/protobuf/internal/service_reflection_test.py \ python/google/protobuf/internal/test_util.py \ diff --git a/autogen.sh b/autogen.sh index 519bb8f3..04d65b16 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,6 +4,8 @@ # be included in the distribution. These files are not checked in because they # are automatically generated. +set -e + # Check that we're being run from the right directory. if test ! -f src/google/protobuf/stubs/common.h; then cat >&2 << __EOF__ @@ -13,6 +15,14 @@ __EOF__ exit 1 fi +# Check that gtest is present. Usually it is already there since the +# directory is set up as an SVN external. +if test ! -e gtest; then + echo "Google Test not present. Fetching gtest-1.3.0 from the web..." + curl http://googletest.googlecode.com/files/gtest-1.3.0.tar.bz2 | tar jx + mv gtest-1.3.0 gtest +fi + set -ex # Temporary hack: Must change C runtime library to "multi-threaded DLL", diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh index 69dd7dae..07219dc1 100755 --- a/generate_descriptor_proto.sh +++ b/generate_descriptor_proto.sh @@ -27,5 +27,7 @@ __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 && \ + ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto cd .. diff --git a/java/pom.xml b/java/pom.xml index 849ef5da..307bc0b7 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -113,6 +113,7 @@ + target/generated-test-sources diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java index e5bdefe3..b059bc98 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -311,6 +311,12 @@ public abstract class AbstractMessage extends AbstractMessageLite } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; + if (defaultInstance == null && + field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + throw new IllegalStateException( + "Message-typed extension lacked default instance: " + + field.getFullName()); + } } } else { field = null; @@ -319,15 +325,28 @@ public abstract class AbstractMessage extends AbstractMessageLite field = type.findFieldByNumber(fieldNumber); } - if (field == null || wireType != - FieldSet.getWireFormatForFieldType( - field.getLiteType(), - field.getOptions().getPacked())) { - // Unknown field or wrong wire type. Skip. + boolean unknown = false; + boolean packed = false; + if (field == null) { + unknown = true; // Unknown field. + } else if (wireType == FieldSet.getWireFormatForFieldType( + field.getLiteType(), + false /* isPacked */)) { + packed = false; + } else if (field.isPackable() && + wireType == FieldSet.getWireFormatForFieldType( + field.getLiteType(), + true /* isPacked */)) { + packed = true; + } else { + unknown = true; // Unknown wire type. + } + + if (unknown) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } - if (field.getOptions().getPacked()) { + if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { @@ -673,13 +692,13 @@ public abstract class AbstractMessage extends AbstractMessageLite } @Override - public BuilderType mergeDelimitedFrom(final InputStream input) + public boolean mergeDelimitedFrom(final InputStream input) throws IOException { return super.mergeDelimitedFrom(input); } @Override - public BuilderType mergeDelimitedFrom( + public boolean mergeDelimitedFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java index 86bf02d8..9210d853 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java @@ -86,7 +86,7 @@ public abstract class AbstractMessageLite implements MessageLite { CodedOutputStream.computeRawVarint32Size(serialized) + serialized); final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize); - codedOutput.writeRawVarint32(getSerializedSize()); + codedOutput.writeRawVarint32(serialized); writeTo(codedOutput); codedOutput.flush(); } @@ -105,13 +105,7 @@ public abstract class AbstractMessageLite implements MessageLite { 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); + return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry()); } // Re-defined here for return type covariance. @@ -275,20 +269,24 @@ public abstract class AbstractMessageLite implements MessageLite { } } - public BuilderType mergeDelimitedFrom( + public boolean mergeDelimitedFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { - final int size = CodedInputStream.readRawVarint32(input); + final int firstByte = input.read(); + if (firstByte == -1) { + return false; + } + final int size = CodedInputStream.readRawVarint32(firstByte, input); final InputStream limitedInput = new LimitedInputStream(input, size); - return mergeFrom(limitedInput, extensionRegistry); + mergeFrom(limitedInput, extensionRegistry); + return true; } - public BuilderType mergeDelimitedFrom(final InputStream input) + public boolean mergeDelimitedFrom(final InputStream input) throws IOException { - final int size = CodedInputStream.readRawVarint32(input); - final InputStream limitedInput = new LimitedInputStream(input, size); - return mergeFrom(limitedInput); + return mergeDelimitedFrom(input, + ExtensionRegistryLite.getEmptyRegistry()); } /** diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java index c83c335c..c043df8b 100644 --- a/java/src/main/java/com/google/protobuf/ByteString.java +++ b/java/src/main/java/com/google/protobuf/ByteString.java @@ -98,6 +98,24 @@ public final class ByteString { return copyFrom(bytes, 0, bytes.length); } + /** + * Copies {@code size} bytes from a {@code java.nio.ByteBuffer} into + * a {@code ByteString}. + */ + public static ByteString copyFrom(final ByteBuffer bytes, final int size) { + final byte[] copy = new byte[size]; + bytes.get(copy); + return new ByteString(copy); + } + + /** + * Copies the remaining bytes from a {@code java.nio.ByteBuffer} into + * a {@code ByteString}. + */ + public static ByteString copyFrom(final ByteBuffer bytes) { + return copyFrom(bytes, bytes.remaining()); + } + /** * Encodes {@code text} into a sequence of bytes using the named charset * and returns the result as a {@code ByteString}. diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java index f339c00e..f0c1051d 100644 --- a/java/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java @@ -84,8 +84,9 @@ public final class CodedInputStream { } lastTag = readRawVarint32(); - if (lastTag == 0) { - // If we actually read zero, that's not a valid tag. + if (WireFormat.getTagFieldNumber(lastTag) == 0) { + // If we actually read zero (or any tag number corresponding to field + // number zero), that's not a valid tag. throw InvalidProtocolBufferException.invalidTag(); } return lastTag; @@ -355,8 +356,26 @@ public final class CodedInputStream { * CodedInputStream buffers its input. */ static int readRawVarint32(final InputStream input) throws IOException { - int result = 0; - int offset = 0; + final int firstByte = input.read(); + if (firstByte == -1) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return readRawVarint32(firstByte, input); + } + + /** + * Like {@link #readRawVarint32(InputStream)}, but expects that the caller + * has already read one byte. This allows the caller to determine if EOF + * has been reached before attempting to read. + */ + static int readRawVarint32(final int firstByte, + final InputStream input) throws IOException { + if ((firstByte & 0x80) == 0) { + return firstByte; + } + + int result = firstByte & 0x7f; + int offset = 7; for (; offset < 32; offset += 7) { final int b = input.read(); if (b == -1) { diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index 0c162d5d..c5e9a04b 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -48,7 +48,7 @@ import java.io.UnsupportedEncodingException; * (given a message object of the type) {@code message.getDescriptorForType()}. * * Descriptors are built from DescriptorProtos, as defined in - * {@code net/proto2/proto/descriptor.proto}. + * {@code google/protobuf/descriptor.proto}. * * @author kenton@google.com Kenton Varda */ @@ -699,6 +699,11 @@ public final class Descriptors { return getOptions().getPacked(); } + /** Can this field be packed? i.e. is it a repeated primitive field? */ + public boolean isPackable() { + return isRepeated() && getLiteType().isPackable(); + } + /** Returns true if the field had an explicitly-defined default value. */ public boolean hasDefaultValue() { return proto.hasDefaultValue(); } @@ -810,39 +815,34 @@ public final class Descriptors { private Object defaultValue; public enum Type { - DOUBLE (FieldDescriptorProto.Type.TYPE_DOUBLE , JavaType.DOUBLE ), - FLOAT (FieldDescriptorProto.Type.TYPE_FLOAT , JavaType.FLOAT ), - INT64 (FieldDescriptorProto.Type.TYPE_INT64 , JavaType.LONG ), - UINT64 (FieldDescriptorProto.Type.TYPE_UINT64 , JavaType.LONG ), - INT32 (FieldDescriptorProto.Type.TYPE_INT32 , JavaType.INT ), - FIXED64 (FieldDescriptorProto.Type.TYPE_FIXED64 , JavaType.LONG ), - FIXED32 (FieldDescriptorProto.Type.TYPE_FIXED32 , JavaType.INT ), - BOOL (FieldDescriptorProto.Type.TYPE_BOOL , JavaType.BOOLEAN ), - STRING (FieldDescriptorProto.Type.TYPE_STRING , JavaType.STRING ), - GROUP (FieldDescriptorProto.Type.TYPE_GROUP , JavaType.MESSAGE ), - MESSAGE (FieldDescriptorProto.Type.TYPE_MESSAGE , JavaType.MESSAGE ), - BYTES (FieldDescriptorProto.Type.TYPE_BYTES , JavaType.BYTE_STRING), - UINT32 (FieldDescriptorProto.Type.TYPE_UINT32 , JavaType.INT ), - ENUM (FieldDescriptorProto.Type.TYPE_ENUM , JavaType.ENUM ), - SFIXED32(FieldDescriptorProto.Type.TYPE_SFIXED32, JavaType.INT ), - SFIXED64(FieldDescriptorProto.Type.TYPE_SFIXED64, JavaType.LONG ), - SINT32 (FieldDescriptorProto.Type.TYPE_SINT32 , JavaType.INT ), - SINT64 (FieldDescriptorProto.Type.TYPE_SINT64 , JavaType.LONG ); - - Type(final FieldDescriptorProto.Type proto, final JavaType javaType) { - this.proto = proto; + DOUBLE (JavaType.DOUBLE ), + FLOAT (JavaType.FLOAT ), + INT64 (JavaType.LONG ), + UINT64 (JavaType.LONG ), + INT32 (JavaType.INT ), + FIXED64 (JavaType.LONG ), + FIXED32 (JavaType.INT ), + BOOL (JavaType.BOOLEAN ), + STRING (JavaType.STRING ), + GROUP (JavaType.MESSAGE ), + MESSAGE (JavaType.MESSAGE ), + BYTES (JavaType.BYTE_STRING), + UINT32 (JavaType.INT ), + ENUM (JavaType.ENUM ), + SFIXED32(JavaType.INT ), + SFIXED64(JavaType.LONG ), + SINT32 (JavaType.INT ), + SINT64 (JavaType.LONG ); + + Type(final JavaType javaType) { this.javaType = javaType; - - if (ordinal() != proto.getNumber() - 1) { - throw new RuntimeException( - "descriptor.proto changed but Desrciptors.java wasn't updated."); - } } - private FieldDescriptorProto.Type proto; private JavaType javaType; - public FieldDescriptorProto.Type toProto() { return proto; } + public FieldDescriptorProto.Type toProto() { + return FieldDescriptorProto.Type.valueOf(ordinal() + 1); + } public JavaType getJavaType() { return javaType; } public static Type valueOf(final FieldDescriptorProto.Type type) { @@ -902,16 +902,10 @@ public final class Descriptors { } // Only repeated primitive fields may be packed. - if (proto.getOptions().getPacked()) { - if (proto.getLabel() != FieldDescriptorProto.Label.LABEL_REPEATED || - proto.getType() == FieldDescriptorProto.Type.TYPE_STRING || - proto.getType() == FieldDescriptorProto.Type.TYPE_GROUP || - proto.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE || - proto.getType() == FieldDescriptorProto.Type.TYPE_BYTES) { - throw new DescriptorValidationException(this, - "[packed = true] can only be specified for repeated primitive " + - "fields."); - } + if (proto.getOptions().getPacked() && !isPackable()) { + throw new DescriptorValidationException(this, + "[packed = true] can only be specified for repeated primitive " + + "fields."); } if (isExtension) { @@ -1030,10 +1024,26 @@ public final class Descriptors { defaultValue = TextFormat.parseUInt64(proto.getDefaultValue()); break; case FLOAT: - defaultValue = Float.valueOf(proto.getDefaultValue()); + if (proto.getDefaultValue().equals("inf")) { + defaultValue = Float.POSITIVE_INFINITY; + } else if (proto.getDefaultValue().equals("-inf")) { + defaultValue = Float.NEGATIVE_INFINITY; + } else if (proto.getDefaultValue().equals("nan")) { + defaultValue = Float.NaN; + } else { + defaultValue = Float.valueOf(proto.getDefaultValue()); + } break; case DOUBLE: - defaultValue = Double.valueOf(proto.getDefaultValue()); + if (proto.getDefaultValue().equals("inf")) { + defaultValue = Double.POSITIVE_INFINITY; + } else if (proto.getDefaultValue().equals("-inf")) { + defaultValue = Double.NEGATIVE_INFINITY; + } else if (proto.getDefaultValue().equals("nan")) { + defaultValue = Double.NaN; + } else { + defaultValue = Double.valueOf(proto.getDefaultValue()); + } break; case BOOL: defaultValue = Boolean.valueOf(proto.getDefaultValue()); @@ -1064,12 +1074,9 @@ public final class Descriptors { "Message type had default value."); } } catch (NumberFormatException e) { - final DescriptorValidationException validationException = - new DescriptorValidationException(this, - "Could not parse default value: \"" + - proto.getDefaultValue() + '\"'); - validationException.initCause(e); - throw validationException; + throw new DescriptorValidationException(this, + "Could not parse default value: \"" + + proto.getDefaultValue() + '\"', e); } } else { // Determine the default default for this field. @@ -1536,14 +1543,7 @@ public final class Descriptors { private DescriptorValidationException( final GenericDescriptor problemDescriptor, final String description) { - this(problemDescriptor, description, null); - } - - private DescriptorValidationException( - final GenericDescriptor problemDescriptor, - final String description, - final Throwable cause) { - super(problemDescriptor.getFullName() + ": " + description, cause); + super(problemDescriptor.getFullName() + ": " + description); // Note that problemDescriptor may be partially uninitialized, so we // don't want to expose it directly to the user. So, we only provide @@ -1553,6 +1553,14 @@ public final class Descriptors { this.description = description; } + private DescriptorValidationException( + final GenericDescriptor problemDescriptor, + final String description, + final Throwable cause) { + this(problemDescriptor, description); + initCause(cause); + } + private DescriptorValidationException( final FileDescriptor problemDescriptor, final String description) { diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java index 87bbd6eb..d4f6ba9e 100644 --- a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java +++ b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java @@ -157,6 +157,11 @@ public final class ExtensionRegistry extends ExtensionRegistryLite { public void add(final GeneratedMessage.GeneratedExtension extension) { if (extension.getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + if (extension.getMessageDefaultInstance() == null) { + throw new IllegalStateException( + "Registered message-type extension had null default instance: " + + extension.getDescriptor().getFullName()); + } add(new ExtensionInfo(extension.getDescriptor(), extension.getMessageDefaultInstance())); } else { diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index 4994faad..b5583ba3 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -789,6 +789,10 @@ public abstract class GeneratedMessage extends AbstractMessage { messageDefaultInstance = (Message) invokeOrDie(getMethodOrDie(type, "getDefaultInstance"), null); + if (messageDefaultInstance == null) { + throw new IllegalStateException( + type.getName() + ".getDefaultInstance() returned null."); + } break; case ENUM: enumValueOf = getMethodOrDie(type, "valueOf", diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java index c68414bd..e327f745 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -303,7 +303,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite { final ExtensionRegistryLite extensionRegistry, final int tag) throws IOException { final FieldSet extensions = - internalGetResult().extensions; + ((ExtendableMessage) internalGetResult()).extensions; final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); @@ -312,15 +312,29 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite { extensionRegistry.findLiteExtensionByNumber( getDefaultInstanceForType(), fieldNumber); - if (extension == null || wireType != - FieldSet.getWireFormatForFieldType( - extension.descriptor.getLiteType(), - extension.descriptor.isPacked())) { - // Unknown field or wrong wire type. Skip. + boolean unknown = false; + boolean packed = false; + if (extension == null) { + unknown = true; // Unknown field. + } else if (wireType == FieldSet.getWireFormatForFieldType( + extension.descriptor.getLiteType(), + false /* isPacked */)) { + packed = false; // Normal, unpacked value. + } else if (extension.descriptor.isRepeated && + extension.descriptor.type.isPackable() && + wireType == FieldSet.getWireFormatForFieldType( + extension.descriptor.getLiteType(), + true /* isPacked */)) { + packed = true; // Packed value. + } else { + unknown = true; // Wrong wire type. + } + + if (unknown) { // Unknown field or wrong wire type. Skip. return input.skipField(tag); } - if (extension.descriptor.isPacked()) { + if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) { @@ -396,7 +410,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite { } protected final void mergeExtensionFields(final MessageType other) { - internalGetResult().extensions.mergeFrom(other.extensions); + ((ExtendableMessage) internalGetResult()).extensions.mergeFrom( + ((ExtendableMessage) other).extensions); } } diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java index c11abdc5..8c29e212 100644 --- a/java/src/main/java/com/google/protobuf/Message.java +++ b/java/src/main/java/com/google/protobuf/Message.java @@ -296,9 +296,9 @@ public interface Message extends MessageLite { Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws IOException; - Builder mergeDelimitedFrom(InputStream input) + boolean mergeDelimitedFrom(InputStream input) throws IOException; - Builder mergeDelimitedFrom(InputStream input, + boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws IOException; } diff --git a/java/src/main/java/com/google/protobuf/MessageLite.java b/java/src/main/java/com/google/protobuf/MessageLite.java index 3ebe9bba..cf7f39e2 100644 --- a/java/src/main/java/com/google/protobuf/MessageLite.java +++ b/java/src/main/java/com/google/protobuf/MessageLite.java @@ -317,14 +317,18 @@ public interface MessageLite { * then the message data. Use * {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in * this format. + * + * @returns True if successful, or false if the stream is at EOF when the + * method starts. Any other error (including reaching EOF during + * parsing) will cause an exception to be thrown. */ - Builder mergeDelimitedFrom(InputStream input) + boolean mergeDelimitedFrom(InputStream input) throws IOException; /** * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions. */ - Builder mergeDelimitedFrom(InputStream input, + boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws IOException; } diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index a855720b..698992f0 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -426,7 +426,7 @@ public final class TextFormat { Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE); private static final Pattern TOKEN = Pattern.compile( "[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier - "[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number + "[.]?[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string Pattern.MULTILINE); diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java index 7f7e4939..26a15d00 100644 --- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -551,19 +553,23 @@ public final class UnknownFieldSet implements MessageLite { return this; } - public Builder mergeDelimitedFrom(InputStream input) + public boolean mergeDelimitedFrom(InputStream input) throws IOException { - final int size = CodedInputStream.readRawVarint32(input); - final InputStream limitedInput = - new AbstractMessage.Builder.LimitedInputStream(input, size); - return mergeFrom(limitedInput, null); + final int firstByte = input.read(); + if (firstByte == -1) { + return false; + } + final int size = CodedInputStream.readRawVarint32(firstByte, input); + final InputStream limitedInput = new LimitedInputStream(input, size); + mergeFrom(limitedInput); + return true; } - public Builder mergeDelimitedFrom( + public boolean mergeDelimitedFrom( InputStream input, ExtensionRegistryLite extensionRegistry) throws IOException { // UnknownFieldSet has no extensions. - return mergeFrom(input); + return mergeDelimitedFrom(input); } public Builder mergeFrom( diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java index 3b0bdcd0..c46f7b0a 100644 --- a/java/src/main/java/com/google/protobuf/WireFormat.java +++ b/java/src/main/java/com/google/protobuf/WireFormat.java @@ -113,10 +113,18 @@ public final class WireFormat { 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), + STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) { + public boolean isPackable() { return false; } + }, + GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) { + public boolean isPackable() { return false; } + }, + MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) { + public boolean isPackable() { return false; } + }, + BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) { + public boolean isPackable() { return false; } + }, UINT32 (JavaType.INT , WIRETYPE_VARINT ), ENUM (JavaType.ENUM , WIRETYPE_VARINT ), SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ), @@ -134,6 +142,8 @@ public final class WireFormat { public JavaType getJavaType() { return javaType; } public int getWireType() { return wireType; } + + public boolean isPackable() { return true; } } // Field numbers for feilds in MessageSet wire format. diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java index 2c59fd0d..c44d6605 100644 --- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -38,6 +38,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequiredForeign; +import protobuf_unittest.UnittestProto.TestUnpackedTypes; import junit.framework.TestCase; @@ -238,6 +239,43 @@ public class AbstractMessageTest extends TestCase { TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); } + public void testUnpackedSerialization() throws Exception { + Message abstractMessage = + new AbstractMessageWrapper(TestUtil.getUnpackedSet()); + + TestUtil.assertUnpackedFieldsSet( + TestUnpackedTypes.parseFrom(abstractMessage.toByteString())); + + assertEquals(TestUtil.getUnpackedSet().toByteString(), + abstractMessage.toByteString()); + } + + public void testParsePackedToUnpacked() throws Exception { + AbstractMessageWrapper.Builder builder = + new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); + AbstractMessageWrapper message = + builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); + TestUtil.assertUnpackedFieldsSet( + (TestUnpackedTypes) message.wrappedMessage); + } + + public void testParseUnpackedToPacked() throws Exception { + AbstractMessageWrapper.Builder builder = + new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); + AbstractMessageWrapper message = + builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); + TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); + } + + public void testUnpackedParsing() throws Exception { + AbstractMessageWrapper.Builder builder = + new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); + AbstractMessageWrapper message = + builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); + TestUtil.assertUnpackedFieldsSet( + (TestUnpackedTypes) message.wrappedMessage); + } + public void testOptimizedForSize() throws Exception { // We're mostly only checking that this class was compiled successfully. TestOptimizedForSize message = diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java index a75a400b..6acd3223 100644 --- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -490,4 +490,18 @@ public class CodedInputStreamTest extends TestCase { assertEquals(0, in.readTag()); assertEquals(5, in.getTotalBytesRead()); } + + public void testInvalidTag() throws Exception { + // Any tag number which corresponds to field number zero is invalid and + // should throw InvalidProtocolBufferException. + for (int i = 0; i < 8; i++) { + try { + CodedInputStream.newInstance(bytes(i)).readTag(); + fail("Should have thrown an exception."); + } catch (InvalidProtocolBufferException e) { + assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(), + e.getMessage()); + } + } + } } diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java index c5c38b27..f41d070e 100644 --- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -30,6 +30,10 @@ package com.google.protobuf; +import com.google.protobuf.DescriptorProtos.DescriptorProto; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; +import com.google.protobuf.DescriptorProtos.FileDescriptorProto; +import com.google.protobuf.Descriptors.DescriptorValidationException; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; @@ -63,6 +67,22 @@ import java.util.Collections; * @author kenton@google.com Kenton Varda */ public class DescriptorsTest extends TestCase { + + // Regression test for bug where referencing a FieldDescriptor.Type value + // before a FieldDescriptorProto.Type value would yield a + // ExceptionInInitializerError. + private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL; + + public void testFieldTypeEnumMapping() throws Exception { + assertEquals(FieldDescriptor.Type.values().length, + FieldDescriptorProto.Type.values().length); + for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) { + FieldDescriptorProto.Type protoType = type.toProto(); + assertEquals("TYPE_" + type.name(), protoType.name()); + assertEquals(type, FieldDescriptor.Type.valueOf(protoType)); + } + } + public void testFileDescriptor() throws Exception { FileDescriptor file = UnittestProto.getDescriptor(); @@ -405,4 +425,35 @@ public class DescriptorsTest extends TestCase { UnittestEnormousDescriptor.getDescriptor() .toProto().getSerializedSize() > 65536); } + + /** + * Tests that the DescriptorValidationException works as intended. + */ + public void testDescriptorValidatorException() throws Exception { + FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder() + .setName("foo.proto") + .addMessageType(DescriptorProto.newBuilder() + .setName("Foo") + .addField(FieldDescriptorProto.newBuilder() + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .setType(FieldDescriptorProto.Type.TYPE_INT32) + .setName("foo") + .setNumber(1) + .setDefaultValue("invalid") + .build()) + .build()) + .build(); + try { + Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, + new FileDescriptor[0]); + fail("DescriptorValidationException expected"); + } catch (DescriptorValidationException e) { + // Expected; check that the error message contains some useful hints + assertTrue(e.getMessage().indexOf("foo") != -1); + assertTrue(e.getMessage().indexOf("Foo") != -1); + assertTrue(e.getMessage().indexOf("invalid") != -1); + assertTrue(e.getCause() instanceof NumberFormatException); + assertTrue(e.getCause().getMessage().indexOf("invalid") != -1); + } + } } diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index cdf60c5e..73c71f31 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -39,6 +39,8 @@ import protobuf_unittest.UnittestProto.ForeignEnum; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; +import protobuf_unittest.UnittestProto.TestPackedTypes; +import protobuf_unittest.UnittestProto.TestUnpackedTypes; import protobuf_unittest.MultipleFilesTestProto; import protobuf_unittest.MessageWithNoOuter; import protobuf_unittest.EnumWithNoOuter; @@ -303,8 +305,15 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertClear(TestAllTypes.getDefaultInstance()); TestUtil.assertClear(TestAllTypes.newBuilder().build()); - assertEquals("\u1234", - TestExtremeDefaultValues.getDefaultInstance().getUtf8String()); + TestExtremeDefaultValues message = + TestExtremeDefaultValues.getDefaultInstance(); + assertEquals("\u1234", message.getUtf8String()); + assertEquals(Double.POSITIVE_INFINITY, message.getInfDouble()); + assertEquals(Double.NEGATIVE_INFINITY, message.getNegInfDouble()); + assertTrue(Double.isNaN(message.getNanDouble())); + assertEquals(Float.POSITIVE_INFINITY, message.getInfFloat()); + assertEquals(Float.NEGATIVE_INFINITY, message.getNegInfFloat()); + assertTrue(Float.isNaN(message.getNanFloat())); } public void testReflectionGetters() throws Exception { @@ -361,6 +370,20 @@ public class GeneratedMessageTest extends TestCase { assertTrue(map.findValueByNumber(12345) == null); } + public void testParsePackedToUnpacked() throws Exception { + TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder(); + TestUnpackedTypes message = + builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); + TestUtil.assertUnpackedFieldsSet(message); + } + + public void testParseUnpackedToPacked() throws Exception { + TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); + TestPackedTypes message = + builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); + TestUtil.assertPackedFieldsSet(message); + } + // ================================================================= // Extensions. @@ -615,4 +638,12 @@ public class GeneratedMessageTest extends TestCase { UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48); assertEquals(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 51); } + + public void testRecursiveMessageDefaultInstance() throws Exception { + UnittestProto.TestRecursiveMessage message = + UnittestProto.TestRecursiveMessage.getDefaultInstance(); + assertTrue(message != null); + assertTrue(message.getA() != null); + assertTrue(message.getA() == message); + } } diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java index d8523ea3..e10322dc 100644 --- a/java/src/test/java/com/google/protobuf/ServiceTest.java +++ b/java/src/test/java/com/google/protobuf/ServiceTest.java @@ -30,7 +30,9 @@ package com.google.protobuf; +import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.MethodDescriptor; +import google.protobuf.no_generic_services_test.UnittestNoGenericServices; import protobuf_unittest.MessageWithNoOuter; import protobuf_unittest.ServiceWithNoOuter; import protobuf_unittest.UnittestProto.TestAllTypes; @@ -44,6 +46,9 @@ import org.easymock.classextension.EasyMock; import org.easymock.classextension.IMocksControl; import org.easymock.IArgumentMatcher; +import java.util.HashSet; +import java.util.Set; + import junit.framework.TestCase; /** @@ -220,6 +225,48 @@ public class ServiceTest extends TestCase { control.verify(); } + public void testNoGenericServices() throws Exception { + // Non-services should be usable. + UnittestNoGenericServices.TestMessage message = + UnittestNoGenericServices.TestMessage.newBuilder() + .setA(123) + .setExtension(UnittestNoGenericServices.testExtension, 456) + .build(); + assertEquals(123, message.getA()); + assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber()); + + // Build a list of the class names nested in UnittestNoGenericServices. + String outerName = "google.protobuf.no_generic_services_test." + + "UnittestNoGenericServices"; + Class outerClass = Class.forName(outerName); + + Set innerClassNames = new HashSet(); + for (Class innerClass : outerClass.getClasses()) { + String fullName = innerClass.getName(); + // Figure out the unqualified name of the inner class. + // Note: Surprisingly, the full name of an inner class will be separated + // from the outer class name by a '$' rather than a '.'. This is not + // mentioned in the documentation for java.lang.Class. I don't want to + // make assumptions, so I'm just going to accept any character as the + // separator. + assertTrue(fullName.startsWith(outerName)); + innerClassNames.add(fullName.substring(outerName.length() + 1)); + } + + // No service class should have been generated. + assertTrue(innerClassNames.contains("TestMessage")); + assertTrue(innerClassNames.contains("TestEnum")); + assertFalse(innerClassNames.contains("TestService")); + + // But descriptors are there. + FileDescriptor file = UnittestNoGenericServices.getDescriptor(); + assertEquals(1, file.getServices().size()); + assertEquals("TestService", file.getServices().get(0).getName()); + assertEquals(1, file.getServices().get(0).getMethods().size()); + assertEquals("Foo", + file.getServices().get(0).getMethods().get(0).getName()); + } + // ================================================================= /** diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java index 805c42ae..db6acb07 100644 --- a/java/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/src/test/java/com/google/protobuf/TestUtil.java @@ -217,6 +217,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; +import protobuf_unittest.UnittestProto.TestUnpackedTypes; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.ForeignEnum; import com.google.protobuf.test.UnittestImport.ImportMessage; @@ -289,6 +290,12 @@ class TestUtil { return builder.build(); } + public static TestUnpackedTypes getUnpackedSet() { + TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder(); + setUnpackedFields(builder); + return builder.build(); + } + public static TestPackedExtensions getPackedExtensionsSet() { TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder(); setPackedExtensions(builder); @@ -955,6 +962,42 @@ class TestUtil { message.addPackedEnum (ForeignEnum.FOREIGN_BAZ); } + /** + * Set every field of {@code message} to a unique value. Must correspond with + * the values applied by {@code setPackedFields}. + */ + public static void setUnpackedFields(TestUnpackedTypes.Builder message) { + message.addUnpackedInt32 (601); + message.addUnpackedInt64 (602); + message.addUnpackedUint32 (603); + message.addUnpackedUint64 (604); + message.addUnpackedSint32 (605); + message.addUnpackedSint64 (606); + message.addUnpackedFixed32 (607); + message.addUnpackedFixed64 (608); + message.addUnpackedSfixed32(609); + message.addUnpackedSfixed64(610); + message.addUnpackedFloat (611); + message.addUnpackedDouble (612); + message.addUnpackedBool (true); + message.addUnpackedEnum (ForeignEnum.FOREIGN_BAR); + // Add a second one of each field. + message.addUnpackedInt32 (701); + message.addUnpackedInt64 (702); + message.addUnpackedUint32 (703); + message.addUnpackedUint64 (704); + message.addUnpackedSint32 (705); + message.addUnpackedSint64 (706); + message.addUnpackedFixed32 (707); + message.addUnpackedFixed64 (708); + message.addUnpackedSfixed32(709); + message.addUnpackedSfixed64(710); + message.addUnpackedFloat (711); + message.addUnpackedDouble (712); + message.addUnpackedBool (false); + message.addUnpackedEnum (ForeignEnum.FOREIGN_BAZ); + } + /** * Assert (using {@code junit.framework.Assert}} that all fields of * {@code message} are set to the values assigned by {@code setPackedFields}. @@ -1004,6 +1047,55 @@ class TestUtil { Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1)); } + /** + * Assert (using {@code junit.framework.Assert}} that all fields of + * {@code message} are set to the values assigned by {@code setUnpackedFields}. + */ + public static void assertUnpackedFieldsSet(TestUnpackedTypes message) { + Assert.assertEquals(2, message.getUnpackedInt32Count ()); + Assert.assertEquals(2, message.getUnpackedInt64Count ()); + Assert.assertEquals(2, message.getUnpackedUint32Count ()); + Assert.assertEquals(2, message.getUnpackedUint64Count ()); + Assert.assertEquals(2, message.getUnpackedSint32Count ()); + Assert.assertEquals(2, message.getUnpackedSint64Count ()); + Assert.assertEquals(2, message.getUnpackedFixed32Count ()); + Assert.assertEquals(2, message.getUnpackedFixed64Count ()); + Assert.assertEquals(2, message.getUnpackedSfixed32Count()); + Assert.assertEquals(2, message.getUnpackedSfixed64Count()); + Assert.assertEquals(2, message.getUnpackedFloatCount ()); + Assert.assertEquals(2, message.getUnpackedDoubleCount ()); + Assert.assertEquals(2, message.getUnpackedBoolCount ()); + Assert.assertEquals(2, message.getUnpackedEnumCount ()); + Assert.assertEquals(601 , message.getUnpackedInt32 (0)); + Assert.assertEquals(602 , message.getUnpackedInt64 (0)); + Assert.assertEquals(603 , message.getUnpackedUint32 (0)); + Assert.assertEquals(604 , message.getUnpackedUint64 (0)); + Assert.assertEquals(605 , message.getUnpackedSint32 (0)); + Assert.assertEquals(606 , message.getUnpackedSint64 (0)); + Assert.assertEquals(607 , message.getUnpackedFixed32 (0)); + Assert.assertEquals(608 , message.getUnpackedFixed64 (0)); + Assert.assertEquals(609 , message.getUnpackedSfixed32(0)); + Assert.assertEquals(610 , message.getUnpackedSfixed64(0)); + Assert.assertEquals(611 , message.getUnpackedFloat (0), 0.0); + Assert.assertEquals(612 , message.getUnpackedDouble (0), 0.0); + Assert.assertEquals(true , message.getUnpackedBool (0)); + Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getUnpackedEnum(0)); + Assert.assertEquals(701 , message.getUnpackedInt32 (1)); + Assert.assertEquals(702 , message.getUnpackedInt64 (1)); + Assert.assertEquals(703 , message.getUnpackedUint32 (1)); + Assert.assertEquals(704 , message.getUnpackedUint64 (1)); + Assert.assertEquals(705 , message.getUnpackedSint32 (1)); + Assert.assertEquals(706 , message.getUnpackedSint64 (1)); + Assert.assertEquals(707 , message.getUnpackedFixed32 (1)); + Assert.assertEquals(708 , message.getUnpackedFixed64 (1)); + Assert.assertEquals(709 , message.getUnpackedSfixed32(1)); + Assert.assertEquals(710 , message.getUnpackedSfixed64(1)); + Assert.assertEquals(711 , message.getUnpackedFloat (1), 0.0); + Assert.assertEquals(712 , message.getUnpackedDouble (1), 0.0); + Assert.assertEquals(false, message.getUnpackedBool (1)); + Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getUnpackedEnum(1)); + } + // =================================================================== // Like above, but for extensions diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 1d73165e..3ea7b2cf 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -68,7 +68,7 @@ public class TextFormatTest extends TestCase { private static String allExtensionsSetText = TestUtil.readTextFromFile( "text_format_unittest_extensions_data.txt"); - private String exoticText = + private static String exoticText = "repeated_int32: -1\n" + "repeated_int32: -2147483648\n" + "repeated_int64: -1\n" + @@ -80,7 +80,13 @@ public class TextFormatTest extends TestCase { "repeated_double: 123.0\n" + "repeated_double: 123.5\n" + "repeated_double: 0.125\n" + + "repeated_double: .125\n" + + "repeated_double: -.125\n" + "repeated_double: 1.23E17\n" + + "repeated_double: 1.23E+17\n" + + "repeated_double: -1.23e-17\n" + + "repeated_double: .23e+17\n" + + "repeated_double: -.23E17\n" + "repeated_double: 1.235E22\n" + "repeated_double: 1.235E-18\n" + "repeated_double: 123.456789\n" + @@ -91,6 +97,10 @@ public class TextFormatTest extends TestCase { "\\341\\210\\264\"\n" + "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n"; + private static String canonicalExoticText = + exoticText.replace(": .", ": 0.").replace(": -.", ": -0.") // short-form double + .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16"); + private String messageSetText = "[protobuf_unittest.TestMessageSetExtension1] {\n" + " i: 123\n" + @@ -231,7 +241,13 @@ public class TextFormatTest extends TestCase { .addRepeatedDouble(123) .addRepeatedDouble(123.5) .addRepeatedDouble(0.125) + .addRepeatedDouble(.125) + .addRepeatedDouble(-.125) + .addRepeatedDouble(123e15) .addRepeatedDouble(123e15) + .addRepeatedDouble(-1.23e-17) + .addRepeatedDouble(.23e17) + .addRepeatedDouble(-23e15) .addRepeatedDouble(123.5e20) .addRepeatedDouble(123.5e-20) .addRepeatedDouble(123.456789) @@ -244,7 +260,7 @@ public class TextFormatTest extends TestCase { .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe")) .build(); - assertEquals(exoticText, message.toString()); + assertEquals(canonicalExoticText, message.toString()); } public void testPrintMessageSet() throws Exception { @@ -319,7 +335,7 @@ public class TextFormatTest extends TestCase { // Too lazy to check things individually. Don't try to debug this // if testPrintExotic() is failing. - assertEquals(exoticText, builder.build().toString()); + assertEquals(canonicalExoticText, builder.build().toString()); } public void testParseMessageSet() throws Exception { diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 6a5bd5de..5ea1dd6a 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -235,6 +235,9 @@ public class WireFormatTest extends TestCase { TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input)); assertEquals(34, input.read()); assertEquals(-1, input.read()); + + // We're at EOF, so parsing again should return null. + assertTrue(TestAllTypes.parseDelimitedFrom(input) == null); } private void assertFieldsInOrder(ByteString data) throws Exception { diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py index 8e3fc2eb..aa4ab969 100755 --- a/python/google/protobuf/descriptor.py +++ b/python/google/protobuf/descriptor.py @@ -44,12 +44,24 @@ file, in types that make this information accessible in Python. __author__ = 'robinson@google.com (Will Robinson)' + +class Error(Exception): + """Base error for this module.""" + + class DescriptorBase(object): """Descriptors base class. This class is the base of all descriptor classes. It provides common options related functionaility. + + Attributes: + has_options: True if the descriptor has non-default options. Usually it + is not necessary to read this -- just call GetOptions() which will + happily return the default instance. However, it's sometimes useful + for efficiency, and also useful inside the protobuf implementation to + avoid some bootstrapping issues. """ def __init__(self, options, options_class_name): @@ -60,6 +72,9 @@ class DescriptorBase(object): self._options = options self._options_class_name = options_class_name + # Does this descriptor have non-default options? + self.has_options = options is not None + def GetOptions(self): """Retrieves descriptor options. @@ -78,7 +93,70 @@ class DescriptorBase(object): return self._options -class Descriptor(DescriptorBase): +class _NestedDescriptorBase(DescriptorBase): + """Common class for descriptors that can be nested.""" + + def __init__(self, options, options_class_name, name, full_name, + file, containing_type, serialized_start=None, + serialized_end=None): + """Constructor. + + Args: + options: Protocol message options or None + to use default message options. + options_class_name: (str) The class name of the above options. + + name: (str) Name of this protocol message type. + full_name: (str) Fully-qualified name of this protocol message type, + which will include protocol "package" name and the name of any + enclosing types. + file: (FileDescriptor) Reference to file info. + containing_type: if provided, this is a nested descriptor, with this + descriptor as parent, otherwise None. + serialized_start: The start index (inclusive) in block in the + file.serialized_pb that describes this descriptor. + serialized_end: The end index (exclusive) in block in the + file.serialized_pb that describes this descriptor. + """ + super(_NestedDescriptorBase, self).__init__( + options, options_class_name) + + self.name = name + # TODO(falk): Add function to calculate full_name instead of having it in + # memory? + self.full_name = full_name + self.file = file + self.containing_type = containing_type + + self._serialized_start = serialized_start + self._serialized_end = serialized_end + + def GetTopLevelContainingType(self): + """Returns the root if this is a nested type, or itself if its the root.""" + desc = self + while desc.containing_type is not None: + desc = desc.containing_type + return desc + + def CopyToProto(self, proto): + """Copies this to the matching proto in descriptor_pb2. + + Args: + proto: An empty proto instance from descriptor_pb2. + + Raises: + Error: If self couldnt be serialized, due to to few constructor arguments. + """ + if (self.file is not None and + self._serialized_start is not None and + self._serialized_end is not None): + proto.ParseFromString(self.file.serialized_pb[ + self._serialized_start:self._serialized_end]) + else: + raise Error('Descriptor does not contain serialization.') + + +class Descriptor(_NestedDescriptorBase): """Descriptor for a protocol message type. @@ -89,10 +167,8 @@ class Descriptor(DescriptorBase): which will include protocol "package" name and the name of any enclosing types. - filename: (str) Name of the .proto file containing this message. - containing_type: (Descriptor) Reference to the descriptor of the - type containing us, or None if we have no containing type. + type containing us, or None if this is top-level. fields: (list of FieldDescriptors) Field descriptors for all fields in this type. @@ -123,20 +199,28 @@ class Descriptor(DescriptorBase): objects as |extensions|, but indexed by "name" attribute of each FieldDescriptor. + is_extendable: Does this type define any extension ranges? + options: (descriptor_pb2.MessageOptions) Protocol message options or None to use default message options. + + file: (FileDescriptor) Reference to file descriptor. """ - def __init__(self, name, full_name, filename, containing_type, - fields, nested_types, enum_types, extensions, options=None): + def __init__(self, name, full_name, filename, containing_type, fields, + nested_types, enum_types, extensions, options=None, + is_extendable=True, extension_ranges=None, file=None, + serialized_start=None, serialized_end=None): """Arguments to __init__() are as described in the description of Descriptor fields above. + + Note that filename is an obsolete argument, that is not used anymore. + Please use file.name to access this as an attribute. """ - super(Descriptor, self).__init__(options, 'MessageOptions') - self.name = name - self.full_name = full_name - self.filename = filename - self.containing_type = containing_type + super(Descriptor, self).__init__( + options, 'MessageOptions', name, full_name, file, + containing_type, serialized_start=serialized_start, + serialized_end=serialized_start) # We have fields in addition to fields_by_name and fields_by_number, # so that: @@ -163,6 +247,20 @@ class Descriptor(DescriptorBase): for extension in self.extensions: extension.extension_scope = self self.extensions_by_name = dict((f.name, f) for f in extensions) + self.is_extendable = is_extendable + self.extension_ranges = extension_ranges + + self._serialized_start = serialized_start + self._serialized_end = serialized_end + + def CopyToProto(self, proto): + """Copies this to a descriptor_pb2.DescriptorProto. + + Args: + proto: An empty descriptor_pb2.DescriptorProto. + """ + # This function is overriden to give a better doc comment. + super(Descriptor, self).CopyToProto(proto) # TODO(robinson): We should have aggressive checking here, @@ -195,6 +293,8 @@ class FieldDescriptor(DescriptorBase): label: (One of the LABEL_* constants below) Tells whether this field is optional, required, or repeated. + has_default_value: (bool) True if this field has a default value defined, + otherwise false. default_value: (Varies) Default value of this field. Only meaningful for non-repeated scalar fields. Repeated fields should always set this to [], and non-repeated composite @@ -272,7 +372,8 @@ class FieldDescriptor(DescriptorBase): def __init__(self, name, full_name, index, number, type, cpp_type, label, default_value, message_type, enum_type, containing_type, - is_extension, extension_scope, options=None): + is_extension, extension_scope, options=None, + has_default_value=True): """The arguments are as described in the description of FieldDescriptor attributes above. @@ -288,6 +389,7 @@ class FieldDescriptor(DescriptorBase): self.type = type self.cpp_type = cpp_type self.label = label + self.has_default_value = has_default_value self.default_value = default_value self.containing_type = containing_type self.message_type = message_type @@ -296,7 +398,7 @@ class FieldDescriptor(DescriptorBase): self.extension_scope = extension_scope -class EnumDescriptor(DescriptorBase): +class EnumDescriptor(_NestedDescriptorBase): """Descriptor for an enum defined in a .proto file. @@ -305,7 +407,6 @@ class EnumDescriptor(DescriptorBase): name: (str) Name of the enum type. full_name: (str) Full name of the type, including package name and any enclosing type(s). - filename: (str) Name of the .proto file in which this appears. values: (list of EnumValueDescriptors) List of the values in this enum. @@ -317,23 +418,41 @@ class EnumDescriptor(DescriptorBase): type of this enum, or None if this is an enum defined at the top level in a .proto file. Set by Descriptor's constructor if we're passed into one. + file: (FileDescriptor) Reference to file descriptor. options: (descriptor_pb2.EnumOptions) Enum options message or None to use default enum options. """ def __init__(self, name, full_name, filename, values, - containing_type=None, options=None): - """Arguments are as described in the attribute description above.""" - super(EnumDescriptor, self).__init__(options, 'EnumOptions') - self.name = name - self.full_name = full_name - self.filename = filename + containing_type=None, options=None, file=None, + serialized_start=None, serialized_end=None): + """Arguments are as described in the attribute description above. + + Note that filename is an obsolete argument, that is not used anymore. + Please use file.name to access this as an attribute. + """ + super(EnumDescriptor, self).__init__( + options, 'EnumOptions', name, full_name, file, + containing_type, serialized_start=serialized_start, + serialized_end=serialized_start) + self.values = values for value in self.values: value.type = self self.values_by_name = dict((v.name, v) for v in values) self.values_by_number = dict((v.number, v) for v in values) - self.containing_type = containing_type + + self._serialized_start = serialized_start + self._serialized_end = serialized_end + + def CopyToProto(self, proto): + """Copies this to a descriptor_pb2.EnumDescriptorProto. + + Args: + proto: An empty descriptor_pb2.EnumDescriptorProto. + """ + # This function is overriden to give a better doc comment. + super(EnumDescriptor, self).CopyToProto(proto) class EnumValueDescriptor(DescriptorBase): @@ -360,7 +479,7 @@ class EnumValueDescriptor(DescriptorBase): self.type = type -class ServiceDescriptor(DescriptorBase): +class ServiceDescriptor(_NestedDescriptorBase): """Descriptor for a service. @@ -372,12 +491,15 @@ class ServiceDescriptor(DescriptorBase): service. options: (descriptor_pb2.ServiceOptions) Service options message or None to use default service options. + file: (FileDescriptor) Reference to file info. """ - def __init__(self, name, full_name, index, methods, options=None): - super(ServiceDescriptor, self).__init__(options, 'ServiceOptions') - self.name = name - self.full_name = full_name + def __init__(self, name, full_name, index, methods, options=None, file=None, + serialized_start=None, serialized_end=None): + super(ServiceDescriptor, self).__init__( + options, 'ServiceOptions', name, full_name, file, + None, serialized_start=serialized_start, + serialized_end=serialized_end) self.index = index self.methods = methods # Set the containing service for each method in this service. @@ -391,6 +513,15 @@ class ServiceDescriptor(DescriptorBase): return method return None + def CopyToProto(self, proto): + """Copies this to a descriptor_pb2.ServiceDescriptorProto. + + Args: + proto: An empty descriptor_pb2.ServiceDescriptorProto. + """ + # This function is overriden to give a better doc comment. + super(ServiceDescriptor, self).CopyToProto(proto) + class MethodDescriptor(DescriptorBase): @@ -423,6 +554,32 @@ class MethodDescriptor(DescriptorBase): self.output_type = output_type +class FileDescriptor(DescriptorBase): + """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto. + + name: name of file, relative to root of source tree. + package: name of the package + serialized_pb: (str) Byte string of serialized + descriptor_pb2.FileDescriptorProto. + """ + + def __init__(self, name, package, options=None, serialized_pb=None): + """Constructor.""" + super(FileDescriptor, self).__init__(options, 'FileOptions') + + self.name = name + self.package = package + self.serialized_pb = serialized_pb + + def CopyToProto(self, proto): + """Copies this to a descriptor_pb2.FileDescriptorProto. + + Args: + proto: An empty descriptor_pb2.FileDescriptorProto. + """ + proto.ParseFromString(self.serialized_pb) + + def _ParseOptions(message, string): """Parses serialized options. @@ -430,4 +587,4 @@ def _ParseOptions(message, string): proto2 files. It must not be used outside proto2. """ message.ParseFromString(string) - return message; + return message diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py index d8a825df..5cc7d6d0 100755 --- a/python/google/protobuf/internal/containers.py +++ b/python/google/protobuf/internal/containers.py @@ -54,8 +54,7 @@ class BaseContainer(object): Args: message_listener: A MessageListener implementation. The RepeatedScalarFieldContainer will call this object's - TransitionToNonempty() method when it transitions from being empty to - being nonempty. + Modified() method when it is modified. """ self._message_listener = message_listener self._values = [] @@ -73,6 +72,9 @@ class BaseContainer(object): # The concrete classes should define __eq__. return not self == other + def __repr__(self): + return repr(self._values) + class RepeatedScalarFieldContainer(BaseContainer): @@ -86,8 +88,7 @@ class RepeatedScalarFieldContainer(BaseContainer): Args: message_listener: A MessageListener implementation. The RepeatedScalarFieldContainer will call this object's - TransitionToNonempty() method when it transitions from being empty to - being nonempty. + Modified() method when it is modified. type_checker: A type_checkers.ValueChecker instance to run on elements inserted into this container. """ @@ -96,44 +97,47 @@ class RepeatedScalarFieldContainer(BaseContainer): def append(self, value): """Appends an item to the list. Similar to list.append().""" - self.insert(len(self._values), value) + self._type_checker.CheckValue(value) + self._values.append(value) + if not self._message_listener.dirty: + self._message_listener.Modified() def insert(self, key, value): """Inserts the item at the specified position. Similar to list.insert().""" self._type_checker.CheckValue(value) self._values.insert(key, value) - self._message_listener.ByteSizeDirty() - if len(self._values) == 1: - self._message_listener.TransitionToNonempty() + if not self._message_listener.dirty: + self._message_listener.Modified() def extend(self, elem_seq): """Extends by appending the given sequence. Similar to list.extend().""" if not elem_seq: return - orig_empty = len(self._values) == 0 new_values = [] for elem in elem_seq: self._type_checker.CheckValue(elem) new_values.append(elem) self._values.extend(new_values) - self._message_listener.ByteSizeDirty() - if orig_empty: - self._message_listener.TransitionToNonempty() + self._message_listener.Modified() + + def MergeFrom(self, other): + """Appends the contents of another repeated field of the same type to this + one. We do not check the types of the individual fields. + """ + self._values.extend(other._values) + self._message_listener.Modified() def remove(self, elem): """Removes an item from the list. Similar to list.remove().""" self._values.remove(elem) - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __setitem__(self, key, value): """Sets the item on the specified position.""" - # No need to call TransitionToNonempty(), since if we're able to - # set the element at this index, we were already nonempty before - # this method was called. - self._message_listener.ByteSizeDirty() self._type_checker.CheckValue(value) self._values[key] = value + self._message_listener.Modified() def __getslice__(self, start, stop): """Retrieves the subset of items from between the specified indices.""" @@ -146,17 +150,17 @@ class RepeatedScalarFieldContainer(BaseContainer): self._type_checker.CheckValue(value) new_values.append(value) self._values[start:stop] = new_values - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __delitem__(self, key): """Deletes the item at the specified position.""" del self._values[key] - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __delslice__(self, start, stop): """Deletes the subset of items from between the specified indices.""" del self._values[start:stop] - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __eq__(self, other): """Compares the current instance with another one.""" @@ -186,8 +190,7 @@ class RepeatedCompositeFieldContainer(BaseContainer): Args: message_listener: A MessageListener implementation. The RepeatedCompositeFieldContainer will call this object's - TransitionToNonempty() method when it transitions from being empty to - being nonempty. + Modified() method when it is modified. message_descriptor: A Descriptor instance describing the protocol type that should be present in this container. We'll use the _concrete_class field of this descriptor when the client calls add(). @@ -199,10 +202,24 @@ class RepeatedCompositeFieldContainer(BaseContainer): new_element = self._message_descriptor._concrete_class() new_element._SetListener(self._message_listener) self._values.append(new_element) - self._message_listener.ByteSizeDirty() - self._message_listener.TransitionToNonempty() + if not self._message_listener.dirty: + self._message_listener.Modified() return new_element + def MergeFrom(self, other): + """Appends the contents of another repeated field of the same type to this + one, copying each individual message. + """ + message_class = self._message_descriptor._concrete_class + listener = self._message_listener + values = self._values + for message in other._values: + new_element = message_class() + new_element._SetListener(listener) + new_element.MergeFrom(message) + values.append(new_element) + listener.Modified() + def __getslice__(self, start, stop): """Retrieves the subset of items from between the specified indices.""" return self._values[start:stop] @@ -210,12 +227,12 @@ class RepeatedCompositeFieldContainer(BaseContainer): def __delitem__(self, key): """Deletes the item at the specified position.""" del self._values[key] - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __delslice__(self, start, stop): """Deletes the subset of items from between the specified indices.""" del self._values[start:stop] - self._message_listener.ByteSizeDirty() + self._message_listener.Modified() def __eq__(self, other): """Compares the current instance with another one.""" diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py index 83d6fe0c..461a30c0 100755 --- a/python/google/protobuf/internal/decoder.py +++ b/python/google/protobuf/internal/decoder.py @@ -28,182 +28,614 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Class for decoding protocol buffer primitives. - -Contains the logic for decoding every logical protocol field type -from one of the 5 physical wire types. +"""Code for decoding protocol buffer primitives. + +This code is very similar to encoder.py -- read the docs for that module first. + +A "decoder" is a function with the signature: + Decode(buffer, pos, end, message, field_dict) +The arguments are: + buffer: The string containing the encoded message. + pos: The current position in the string. + end: The position in the string where the current message ends. May be + less than len(buffer) if we're reading a sub-message. + message: The message object into which we're parsing. + field_dict: message._fields (avoids a hashtable lookup). +The decoder reads the field and stores it into field_dict, returning the new +buffer position. A decoder for a repeated field may proactively decode all of +the elements of that field, if they appear consecutively. + +Note that decoders may throw any of the following: + IndexError: Indicates a truncated message. + struct.error: Unpacking of a fixed-width field failed. + message.DecodeError: Other errors. + +Decoders are expected to raise an exception if they are called with pos > end. +This allows callers to be lax about bounds checking: it's fineto read past +"end" as long as you are sure that someone else will notice and throw an +exception later on. + +Something up the call stack is expected to catch IndexError and struct.error +and convert them to message.DecodeError. + +Decoders are constructed using decoder constructors with the signature: + MakeDecoder(field_number, is_repeated, is_packed, key, new_default) +The arguments are: + field_number: The field number of the field we want to decode. + is_repeated: Is the field a repeated field? (bool) + is_packed: Is the field a packed field? (bool) + key: The key to use when looking up the field within field_dict. + (This is actually the FieldDescriptor but nothing in this + file should depend on that.) + new_default: A function which takes a message object as a parameter and + returns a new instance of the default value for this field. + (This is called for repeated fields and sub-messages, when an + instance does not already exist.) + +As with encoders, we define a decoder constructor for every type of field. +Then, for every field of every message class we construct an actual decoder. +That decoder goes into a dict indexed by tag, so when we decode a message +we repeatedly read a tag, look up the corresponding decoder, and invoke it. """ -__author__ = 'robinson@google.com (Will Robinson)' +__author__ = 'kenton@google.com (Kenton Varda)' import struct -from google.protobuf import message -from google.protobuf.internal import input_stream +from google.protobuf.internal import encoder from google.protobuf.internal import wire_format +from google.protobuf import message +# This is not for optimization, but rather to avoid conflicts with local +# variables named "message". +_DecodeError = message.DecodeError + + +def _VarintDecoder(mask): + """Return an encoder for a basic varint value (does not include tag). + + Decoded values will be bitwise-anded with the given mask before being + returned, e.g. to limit them to 32 bits. The returned decoder does not + take the usual "end" parameter -- the caller is expected to do bounds checking + after the fact (often the caller can defer such checking until later). The + decoder returns a (value, new_pos) pair. + """ + + local_ord = ord + def DecodeVarint(buffer, pos): + result = 0 + shift = 0 + while 1: + b = local_ord(buffer[pos]) + result |= ((b & 0x7f) << shift) + pos += 1 + if not (b & 0x80): + result &= mask + return (result, pos) + shift += 7 + if shift >= 64: + raise _DecodeError('Too many bytes when decoding varint.') + return DecodeVarint + + +def _SignedVarintDecoder(mask): + """Like _VarintDecoder() but decodes signed values.""" + + local_ord = ord + def DecodeVarint(buffer, pos): + result = 0 + shift = 0 + while 1: + b = local_ord(buffer[pos]) + result |= ((b & 0x7f) << shift) + pos += 1 + if not (b & 0x80): + if result > 0x7fffffffffffffff: + result -= (1 << 64) + result |= ~mask + else: + result &= mask + return (result, pos) + shift += 7 + if shift >= 64: + raise _DecodeError('Too many bytes when decoding varint.') + return DecodeVarint + + +_DecodeVarint = _VarintDecoder((1 << 64) - 1) +_DecodeSignedVarint = _SignedVarintDecoder((1 << 64) - 1) + +# Use these versions for values which must be limited to 32 bits. +_DecodeVarint32 = _VarintDecoder((1 << 32) - 1) +_DecodeSignedVarint32 = _SignedVarintDecoder((1 << 32) - 1) + + +def ReadTag(buffer, pos): + """Read a tag from the buffer, and return a (tag_bytes, new_pos) tuple. + + We return the raw bytes of the tag rather than decoding them. The raw + bytes can then be used to look up the proper decoder. This effectively allows + us to trade some work that would be done in pure-python (decoding a varint) + for work that is done in C (searching for a byte string in a hash table). + In a low-level language it would be much cheaper to decode the varint and + use that, but not in Python. + """ + + start = pos + while ord(buffer[pos]) & 0x80: + pos += 1 + pos += 1 + return (buffer[start:pos], pos) + + +# -------------------------------------------------------------------- + + +def _SimpleDecoder(wire_type, decode_value): + """Return a constructor for a decoder for fields of a particular type. + + Args: + wire_type: The field's wire type. + decode_value: A function which decodes an individual value, e.g. + _DecodeVarint() + """ + + def SpecificDecoder(field_number, is_repeated, is_packed, key, new_default): + if is_packed: + local_DecodeVarint = _DecodeVarint + def DecodePackedField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + (endpoint, pos) = local_DecodeVarint(buffer, pos) + endpoint += pos + if endpoint > end: + raise _DecodeError('Truncated message.') + while pos < endpoint: + (element, pos) = decode_value(buffer, pos) + value.append(element) + if pos > endpoint: + del value[-1] # Discard corrupt value. + raise _DecodeError('Packed element was truncated.') + return pos + return DecodePackedField + elif is_repeated: + tag_bytes = encoder.TagBytes(field_number, wire_type) + tag_len = len(tag_bytes) + def DecodeRepeatedField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + while 1: + (element, new_pos) = decode_value(buffer, pos) + value.append(element) + # Predict that the next tag is another copy of the same repeated + # field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos >= end: + # Prediction failed. Return. + if new_pos > end: + raise _DecodeError('Truncated message.') + return new_pos + return DecodeRepeatedField + else: + def DecodeField(buffer, pos, end, message, field_dict): + (field_dict[key], pos) = decode_value(buffer, pos) + if pos > end: + del field_dict[key] # Discard corrupt value. + raise _DecodeError('Truncated message.') + return pos + return DecodeField + + return SpecificDecoder + + +def _ModifiedDecoder(wire_type, decode_value, modify_value): + """Like SimpleDecoder but additionally invokes modify_value on every value + before storing it. Usually modify_value is ZigZagDecode. + """ + + # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but + # not enough to make a significant difference. + + def InnerDecode(buffer, pos): + (result, new_pos) = decode_value(buffer, pos) + return (modify_value(result), new_pos) + return _SimpleDecoder(wire_type, InnerDecode) + + +def _StructPackDecoder(wire_type, format): + """Return a constructor for a decoder for a fixed-width field. + + Args: + wire_type: The field's wire type. + format: The format string to pass to struct.unpack(). + """ + + value_size = struct.calcsize(format) + local_unpack = struct.unpack + + # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but + # not enough to make a significant difference. + + # Note that we expect someone up-stack to catch struct.error and convert + # it to _DecodeError -- this way we don't have to set up exception- + # handling blocks every time we parse one value. + + def InnerDecode(buffer, pos): + new_pos = pos + value_size + result = local_unpack(format, buffer[pos:new_pos])[0] + return (result, new_pos) + return _SimpleDecoder(wire_type, InnerDecode) + + +# -------------------------------------------------------------------- + + +Int32Decoder = EnumDecoder = _SimpleDecoder( + wire_format.WIRETYPE_VARINT, _DecodeSignedVarint32) + +Int64Decoder = _SimpleDecoder( + wire_format.WIRETYPE_VARINT, _DecodeSignedVarint) + +UInt32Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint32) +UInt64Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint) + +SInt32Decoder = _ModifiedDecoder( + wire_format.WIRETYPE_VARINT, _DecodeVarint32, wire_format.ZigZagDecode) +SInt64Decoder = _ModifiedDecoder( + wire_format.WIRETYPE_VARINT, _DecodeVarint, wire_format.ZigZagDecode) + +# Note that Python conveniently guarantees that when using the '<' prefix on +# formats, they will also have the same size across all platforms (as opposed +# to without the prefix, where their sizes depend on the C compiler's basic +# type sizes). +Fixed32Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, ' end: + raise _DecodeError('Truncated string.') + value.append(local_unicode(buffer[pos:new_pos], 'utf-8')) + # Predict that the next tag is another copy of the same repeated field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos == end: + # Prediction failed. Return. + return new_pos + return DecodeRepeatedField + else: + def DecodeField(buffer, pos, end, message, field_dict): + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated string.') + field_dict[key] = local_unicode(buffer[pos:new_pos], 'utf-8') + return new_pos + return DecodeField + + +def BytesDecoder(field_number, is_repeated, is_packed, key, new_default): + """Returns a decoder for a bytes field.""" + + local_DecodeVarint = _DecodeVarint + + assert not is_packed + if is_repeated: + tag_bytes = encoder.TagBytes(field_number, + wire_format.WIRETYPE_LENGTH_DELIMITED) + tag_len = len(tag_bytes) + def DecodeRepeatedField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + while 1: + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated string.') + value.append(buffer[pos:new_pos]) + # Predict that the next tag is another copy of the same repeated field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos == end: + # Prediction failed. Return. + return new_pos + return DecodeRepeatedField + else: + def DecodeField(buffer, pos, end, message, field_dict): + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated string.') + field_dict[key] = buffer[pos:new_pos] + return new_pos + return DecodeField + + +def GroupDecoder(field_number, is_repeated, is_packed, key, new_default): + """Returns a decoder for a group field.""" + + end_tag_bytes = encoder.TagBytes(field_number, + wire_format.WIRETYPE_END_GROUP) + end_tag_len = len(end_tag_bytes) + + assert not is_packed + if is_repeated: + tag_bytes = encoder.TagBytes(field_number, + wire_format.WIRETYPE_START_GROUP) + tag_len = len(tag_bytes) + def DecodeRepeatedField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + while 1: + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + # Read sub-message. + pos = value.add()._InternalParse(buffer, pos, end) + # Read end tag. + new_pos = pos+end_tag_len + if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: + raise _DecodeError('Missing group end tag.') + # Predict that the next tag is another copy of the same repeated field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos == end: + # Prediction failed. Return. + return new_pos + return DecodeRepeatedField + else: + def DecodeField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + # Read sub-message. + pos = value._InternalParse(buffer, pos, end) + # Read end tag. + new_pos = pos+end_tag_len + if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: + raise _DecodeError('Missing group end tag.') + return new_pos + return DecodeField + + +def MessageDecoder(field_number, is_repeated, is_packed, key, new_default): + """Returns a decoder for a message field.""" + + local_DecodeVarint = _DecodeVarint + + assert not is_packed + if is_repeated: + tag_bytes = encoder.TagBytes(field_number, + wire_format.WIRETYPE_LENGTH_DELIMITED) + tag_len = len(tag_bytes) + def DecodeRepeatedField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + while 1: + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + # Read length. + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated message.') + # Read sub-message. + if value.add()._InternalParse(buffer, pos, new_pos) != new_pos: + # The only reason _InternalParse would return early is if it + # encountered an end-group tag. + raise _DecodeError('Unexpected end-group tag.') + # Predict that the next tag is another copy of the same repeated field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos == end: + # Prediction failed. Return. + return new_pos + return DecodeRepeatedField + else: + def DecodeField(buffer, pos, end, message, field_dict): + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + # Read length. + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated message.') + # Read sub-message. + if value._InternalParse(buffer, pos, new_pos) != new_pos: + # The only reason _InternalParse would return early is if it encountered + # an end-group tag. + raise _DecodeError('Unexpected end-group tag.') + return new_pos + return DecodeField + + +# -------------------------------------------------------------------- + +MESSAGE_SET_ITEM_TAG = encoder.TagBytes(1, wire_format.WIRETYPE_START_GROUP) + +def MessageSetItemDecoder(extensions_by_number): + """Returns a decoder for a MessageSet item. + + The parameter is the _extensions_by_number map for the message class. + + The message set message looks like this: + message MessageSet { + repeated group Item = 1 { + required int32 type_id = 2; + required string message = 3; + } + } + """ + + type_id_tag_bytes = encoder.TagBytes(2, wire_format.WIRETYPE_VARINT) + message_tag_bytes = encoder.TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED) + item_end_tag_bytes = encoder.TagBytes(1, wire_format.WIRETYPE_END_GROUP) + + local_ReadTag = ReadTag + local_DecodeVarint = _DecodeVarint + local_SkipField = SkipField + + def DecodeItem(buffer, pos, end, message, field_dict): + type_id = -1 + message_start = -1 + message_end = -1 + + # Technically, type_id and message can appear in any order, so we need + # a little loop here. + while 1: + (tag_bytes, pos) = local_ReadTag(buffer, pos) + if tag_bytes == type_id_tag_bytes: + (type_id, pos) = local_DecodeVarint(buffer, pos) + elif tag_bytes == message_tag_bytes: + (size, message_start) = local_DecodeVarint(buffer, pos) + pos = message_end = message_start + size + elif tag_bytes == item_end_tag_bytes: + break + else: + pos = SkipField(buffer, pos, end, tag_bytes) + if pos == -1: + raise _DecodeError('Missing group end tag.') + + if pos > end: + raise _DecodeError('Truncated message.') + + if type_id == -1: + raise _DecodeError('MessageSet item missing type_id.') + if message_start == -1: + raise _DecodeError('MessageSet item missing message.') + + extension = extensions_by_number.get(type_id) + if extension is not None: + value = field_dict.get(extension) + if value is None: + value = field_dict.setdefault( + extension, extension.message_type._concrete_class()) + if value._InternalParse(buffer, message_start,message_end) != message_end: + # The only reason _InternalParse would return early is if it encountered + # an end-group tag. + raise _DecodeError('Unexpected end-group tag.') + + return pos + + return DecodeItem + +# -------------------------------------------------------------------- +# Optimization is not as heavy here because calls to SkipField() are rare, +# except for handling end-group tags. + +def _SkipVarint(buffer, pos, end): + """Skip a varint value. Returns the new position.""" + + while ord(buffer[pos]) & 0x80: + pos += 1 + pos += 1 + if pos > end: + raise _DecodeError('Truncated message.') + return pos + +def _SkipFixed64(buffer, pos, end): + """Skip a fixed64 value. Returns the new position.""" + + pos += 8 + if pos > end: + raise _DecodeError('Truncated message.') + return pos + +def _SkipLengthDelimited(buffer, pos, end): + """Skip a length-delimited value. Returns the new position.""" + + (size, pos) = _DecodeVarint(buffer, pos) + pos += size + if pos > end: + raise _DecodeError('Truncated message.') + return pos + +def _SkipGroup(buffer, pos, end): + """Skip sub-group. Returns the new position.""" + + while 1: + (tag_bytes, pos) = ReadTag(buffer, pos) + new_pos = SkipField(buffer, pos, end, tag_bytes) + if new_pos == -1: + return pos + pos = new_pos + +def _EndGroup(buffer, pos, end): + """Skipping an END_GROUP tag returns -1 to tell the parent loop to break.""" + + return -1 + +def _SkipFixed32(buffer, pos, end): + """Skip a fixed32 value. Returns the new position.""" + + pos += 4 + if pos > end: + raise _DecodeError('Truncated message.') + return pos + +def _RaiseInvalidWireType(buffer, pos, end): + """Skip function for unknown wire types. Raises an exception.""" + + raise _DecodeError('Tag had invalid wire type.') + +def _FieldSkipper(): + """Constructs the SkipField function.""" + + WIRETYPE_TO_SKIPPER = [ + _SkipVarint, + _SkipFixed64, + _SkipLengthDelimited, + _SkipGroup, + _EndGroup, + _SkipFixed32, + _RaiseInvalidWireType, + _RaiseInvalidWireType, + ] + + wiretype_mask = wire_format.TAG_TYPE_MASK + local_ord = ord + + def SkipField(buffer, pos, end, tag_bytes): + """Skips a field with the specified tag. + + |pos| should point to the byte immediately after the tag. + + Returns: + The new position (after the tag value), or -1 if the tag is an end-group + tag (in which case the calling loop should break). + """ -# Note that much of this code is ported from //net/proto/ProtocolBuffer, and -# that the interface is strongly inspired by WireFormat from the C++ proto2 -# implementation. - - -class Decoder(object): - - """Decodes logical protocol buffer fields from the wire.""" + # The wire type is always in the first byte since varints are little-endian. + wire_type = local_ord(tag_bytes[0]) & wiretype_mask + return WIRETYPE_TO_SKIPPER[wire_type](buffer, pos, end) - def __init__(self, s): - """Initializes the decoder to read from s. + return SkipField - Args: - s: An immutable sequence of bytes, which must be accessible - via the Python buffer() primitive (i.e., buffer(s)). - """ - self._stream = input_stream.InputStream(s) - - def EndOfStream(self): - """Returns true iff we've reached the end of the bytes we're reading.""" - return self._stream.EndOfStream() - - def Position(self): - """Returns the 0-indexed position in |s|.""" - return self._stream.Position() - - def ReadFieldNumberAndWireType(self): - """Reads a tag from the wire. Returns a (field_number, wire_type) pair.""" - tag_and_type = self.ReadUInt32() - return wire_format.UnpackTag(tag_and_type) - - def SkipBytes(self, bytes): - """Skips the specified number of bytes on the wire.""" - self._stream.SkipBytes(bytes) - - # Note that the Read*() methods below are not exactly symmetrical with the - # corresponding Encoder.Append*() methods. Those Encoder methods first - # encode a tag, but the Read*() methods below assume that the tag has already - # been read, and that the client wishes to read a field of the specified type - # starting at the current position. - - def ReadInt32(self): - """Reads and returns a signed, varint-encoded, 32-bit integer.""" - return self._stream.ReadVarint32() - - def ReadInt64(self): - """Reads and returns a signed, varint-encoded, 64-bit integer.""" - return self._stream.ReadVarint64() - - def ReadUInt32(self): - """Reads and returns an signed, varint-encoded, 32-bit integer.""" - return self._stream.ReadVarUInt32() - - def ReadUInt64(self): - """Reads and returns an signed, varint-encoded,64-bit integer.""" - return self._stream.ReadVarUInt64() - - def ReadSInt32(self): - """Reads and returns a signed, zigzag-encoded, varint-encoded, - 32-bit integer.""" - return wire_format.ZigZagDecode(self._stream.ReadVarUInt32()) - - def ReadSInt64(self): - """Reads and returns a signed, zigzag-encoded, varint-encoded, - 64-bit integer.""" - return wire_format.ZigZagDecode(self._stream.ReadVarUInt64()) - - def ReadFixed32(self): - """Reads and returns an unsigned, fixed-width, 32-bit integer.""" - return self._stream.ReadLittleEndian32() - - def ReadFixed64(self): - """Reads and returns an unsigned, fixed-width, 64-bit integer.""" - return self._stream.ReadLittleEndian64() - - def ReadSFixed32(self): - """Reads and returns a signed, fixed-width, 32-bit integer.""" - value = self._stream.ReadLittleEndian32() - if value >= (1 << 31): - value -= (1 << 32) - return value - - def ReadSFixed64(self): - """Reads and returns a signed, fixed-width, 64-bit integer.""" - value = self._stream.ReadLittleEndian64() - if value >= (1 << 63): - value -= (1 << 64) - return value - - def ReadFloat(self): - """Reads and returns a 4-byte floating-point number.""" - serialized = self._stream.ReadBytes(4) - 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(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, serialized)[0] - - def ReadBool(self): - """Reads and returns a bool.""" - i = self._stream.ReadVarUInt32() - return bool(i) - - def ReadEnum(self): - """Reads and returns an enum value.""" - return self._stream.ReadVarUInt32() - - def ReadString(self): - """Reads and returns a length-delimited string.""" - bytes = self.ReadBytes() - return unicode(bytes, 'utf-8') - - def ReadBytes(self): - """Reads and returns a length-delimited byte sequence.""" - length = self._stream.ReadVarUInt32() - return self._stream.ReadBytes(length) - - def ReadMessageInto(self, msg): - """Calls msg.MergeFromString() to merge - length-delimited serialized message data into |msg|. - - REQUIRES: The decoder must be positioned at the serialized "length" - prefix to a length-delmiited serialized message. - - POSTCONDITION: The decoder is positioned just after the - serialized message, and we have merged those serialized - contents into |msg|. - """ - length = self._stream.ReadVarUInt32() - sub_buffer = self._stream.GetSubBuffer(length) - num_bytes_used = msg.MergeFromString(sub_buffer) - if num_bytes_used != length: - raise message.DecodeError( - 'Submessage told to deserialize from %d-byte encoding, ' - 'but used only %d bytes' % (length, num_bytes_used)) - self._stream.SkipBytes(num_bytes_used) - - def ReadGroupInto(self, expected_field_number, group): - """Calls group.MergeFromString() to merge - END_GROUP-delimited serialized message data into |group|. - We'll raise an exception if we don't find an END_GROUP - tag immediately after the serialized message contents. - - REQUIRES: The decoder is positioned just after the START_GROUP - tag for this group. - - POSTCONDITION: The decoder is positioned just after the - END_GROUP tag for this group, and we have merged - the contents of the group into |group|. - """ - sub_buffer = self._stream.GetSubBuffer() # No a priori length limit. - num_bytes_used = group.MergeFromString(sub_buffer) - if num_bytes_used < 0: - raise message.DecodeError('Group message reported negative bytes read.') - self._stream.SkipBytes(num_bytes_used) - field_number, field_type = self.ReadFieldNumberAndWireType() - if field_type != wire_format.WIRETYPE_END_GROUP: - raise message.DecodeError('Group message did not end with an END_GROUP.') - if field_number != expected_field_number: - raise message.DecodeError('END_GROUP tag had field ' - 'number %d, was expecting field number %d' % ( - field_number, expected_field_number)) - # We're now positioned just after the END_GROUP tag. Perfect. +SkipField = _FieldSkipper() diff --git a/python/google/protobuf/internal/decoder_test.py b/python/google/protobuf/internal/decoder_test.py deleted file mode 100755 index 98e46472..00000000 --- a/python/google/protobuf/internal/decoder_test.py +++ /dev/null @@ -1,256 +0,0 @@ -#! /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. - -"""Test for google.protobuf.internal.decoder.""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import struct -import unittest -from google.protobuf.internal import decoder -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 - - -class DecoderTest(unittest.TestCase): - - def setUp(self): - self.mox = mox.Mox() - self.mock_stream = self.mox.CreateMock(input_stream.InputStream) - self.mock_message = self.mox.CreateMock(message.Message) - - def testReadFieldNumberAndWireType(self): - # Test field numbers that will require various varint sizes. - for expected_field_number in (1, 15, 16, 2047, 2048): - for expected_wire_type in range(6): # Highest-numbered wiretype is 5. - e = encoder.Encoder() - e.AppendTag(expected_field_number, expected_wire_type) - s = e.ToString() - d = decoder.Decoder(s) - field_number, wire_type = d.ReadFieldNumberAndWireType() - self.assertEqual(expected_field_number, field_number) - self.assertEqual(expected_wire_type, wire_type) - - def ReadScalarTestHelper(self, test_name, decoder_method, expected_result, - expected_stream_method_name, - stream_method_return, *args): - """Helper for testReadScalars below. - - Calls one of the Decoder.Read*() methods and ensures that the results are - as expected. - - Args: - test_name: Name of this test, used for logging only. - decoder_method: Unbound decoder.Decoder method to call. - expected_result: Value we expect returned from decoder_method(). - expected_stream_method_name: (string) Name of the InputStream - method we expect Decoder to call to actually read the value - on the wire. - stream_method_return: Value our mocked-out stream method should - return to the decoder. - args: Additional arguments that we expect to be passed to the - stream method. - """ - logging.info('Testing %s scalar input.\n' - 'Calling %r(), and expecting that to call the ' - 'stream method %s(%r), which will return %r. Finally, ' - 'expecting the Decoder method to return %r'% ( - test_name, decoder_method, - expected_stream_method_name, args, stream_method_return, - expected_result)) - - d = decoder.Decoder('') - d._stream = self.mock_stream - if decoder_method in (decoder.Decoder.ReadString, - decoder.Decoder.ReadBytes): - self.mock_stream.ReadVarUInt32().AndReturn(len(stream_method_return)) - # We have to use names instead of methods to work around some - # mox weirdness. (ResetAll() is overzealous). - expected_stream_method = getattr(self.mock_stream, - expected_stream_method_name) - expected_stream_method(*args).AndReturn(stream_method_return) - - self.mox.ReplayAll() - result = decoder_method(d) - self.assertEqual(expected_result, result) - self.assert_(isinstance(result, type(expected_result))) - 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 = [ - ['int32', decoder.Decoder.ReadInt32, 0, 'ReadVarint32', 0], - ['int64', decoder.Decoder.ReadInt64, 0, 'ReadVarint64', 0], - ['uint32', decoder.Decoder.ReadUInt32, 0, 'ReadVarUInt32', 0], - ['uint64', decoder.Decoder.ReadUInt64, 0, 'ReadVarUInt64', 0], - ['fixed32', decoder.Decoder.ReadFixed32, 0xffffffff, - 'ReadLittleEndian32', 0xffffffff], - ['fixed64', decoder.Decoder.ReadFixed64, 0xffffffffffffffff, - 'ReadLittleEndian64', 0xffffffffffffffff], - ['sfixed32', decoder.Decoder.ReadSFixed32, long(-1), - 'ReadLittleEndian32', long(0xffffffff)], - ['sfixed64', decoder.Decoder.ReadSFixed64, long(-1), - 'ReadLittleEndian64', 0xffffffffffffffff], - ['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, - unicode(test_string, 'utf-8'), 'ReadBytes', test_string, - len(test_string)], - ['utf8-string', decoder.Decoder.ReadString, - unicode(test_string, 'utf-8'), 'ReadBytes', test_string, - len(test_string)], - ['bytes', decoder.Decoder.ReadBytes, - test_string, 'ReadBytes', test_string, len(test_string)], - # We test zigzag decoding routines more extensively below. - ['sint32', decoder.Decoder.ReadSInt32, -1, 'ReadVarUInt32', 1], - ['sint64', decoder.Decoder.ReadSInt64, -1, 'ReadVarUInt64', 1], - ] - # Ensure that we're testing different Decoder methods and using - # different test names in all test cases above. - self.assertEqual(len(scalar_tests), len(set(t[0] for t in scalar_tests))) - self.assert_(len(scalar_tests) >= len(set(t[1] for t in scalar_tests))) - for args in scalar_tests: - self.ReadScalarTestHelper(*args) - - def testReadMessageInto(self): - length = 23 - def Test(simulate_error): - d = decoder.Decoder('') - d._stream = self.mock_stream - self.mock_stream.ReadVarUInt32().AndReturn(length) - sub_buffer = object() - self.mock_stream.GetSubBuffer(length).AndReturn(sub_buffer) - - if simulate_error: - self.mock_message.MergeFromString(sub_buffer).AndReturn(length - 1) - self.mox.ReplayAll() - self.assertRaises( - message.DecodeError, d.ReadMessageInto, self.mock_message) - else: - self.mock_message.MergeFromString(sub_buffer).AndReturn(length) - self.mock_stream.SkipBytes(length) - self.mox.ReplayAll() - d.ReadMessageInto(self.mock_message) - - self.mox.VerifyAll() - self.mox.ResetAll() - - Test(simulate_error=False) - Test(simulate_error=True) - - def testReadGroupInto_Success(self): - # Test both the empty and nonempty cases. - for num_bytes in (5, 0): - field_number = expected_field_number = 10 - d = decoder.Decoder('') - d._stream = self.mock_stream - sub_buffer = object() - self.mock_stream.GetSubBuffer().AndReturn(sub_buffer) - self.mock_message.MergeFromString(sub_buffer).AndReturn(num_bytes) - self.mock_stream.SkipBytes(num_bytes) - self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag( - field_number, wire_format.WIRETYPE_END_GROUP)) - self.mox.ReplayAll() - d.ReadGroupInto(expected_field_number, self.mock_message) - self.mox.VerifyAll() - self.mox.ResetAll() - - def ReadGroupInto_FailureTestHelper(self, bytes_read): - d = decoder.Decoder('') - d._stream = self.mock_stream - sub_buffer = object() - self.mock_stream.GetSubBuffer().AndReturn(sub_buffer) - self.mock_message.MergeFromString(sub_buffer).AndReturn(bytes_read) - return d - - def testReadGroupInto_NegativeBytesReported(self): - expected_field_number = 10 - d = self.ReadGroupInto_FailureTestHelper(bytes_read=-1) - self.mox.ReplayAll() - self.assertRaises(message.DecodeError, - d.ReadGroupInto, expected_field_number, - self.mock_message) - self.mox.VerifyAll() - - def testReadGroupInto_NoEndGroupTag(self): - field_number = expected_field_number = 10 - num_bytes = 5 - d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes) - self.mock_stream.SkipBytes(num_bytes) - # Right field number, wrong wire type. - self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag( - field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)) - self.mox.ReplayAll() - self.assertRaises(message.DecodeError, - d.ReadGroupInto, expected_field_number, - self.mock_message) - self.mox.VerifyAll() - - def testReadGroupInto_WrongFieldNumberInEndGroupTag(self): - expected_field_number = 10 - field_number = expected_field_number + 1 - num_bytes = 5 - d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes) - self.mock_stream.SkipBytes(num_bytes) - # Wrong field number, right wire type. - self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag( - field_number, wire_format.WIRETYPE_END_GROUP)) - self.mox.ReplayAll() - self.assertRaises(message.DecodeError, - d.ReadGroupInto, expected_field_number, - self.mock_message) - self.mox.VerifyAll() - - def testSkipBytes(self): - d = decoder.Decoder('') - num_bytes = 1024 - self.mock_stream.SkipBytes(num_bytes) - d._stream = self.mock_stream - self.mox.ReplayAll() - d.SkipBytes(num_bytes) - self.mox.VerifyAll() - -if __name__ == '__main__': - unittest.main() diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index eb9f2be8..05c27452 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -35,16 +35,30 @@ __author__ = 'robinson@google.com (Will Robinson)' import unittest +from google.protobuf import unittest_import_pb2 +from google.protobuf import unittest_pb2 from google.protobuf import descriptor_pb2 from google.protobuf import descriptor +from google.protobuf import text_format + + +TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """ +name: 'TestEmptyMessage' +""" + class DescriptorTest(unittest.TestCase): def setUp(self): + self.my_file = descriptor.FileDescriptor( + name='some/filename/some.proto', + package='protobuf_unittest' + ) self.my_enum = descriptor.EnumDescriptor( name='ForeignEnum', full_name='protobuf_unittest.ForeignEnum', - filename='ForeignEnum', + filename=None, + file=self.my_file, values=[ descriptor.EnumValueDescriptor(name='FOREIGN_FOO', index=0, number=4), descriptor.EnumValueDescriptor(name='FOREIGN_BAR', index=1, number=5), @@ -53,7 +67,8 @@ class DescriptorTest(unittest.TestCase): self.my_message = descriptor.Descriptor( name='NestedMessage', full_name='protobuf_unittest.TestAllTypes.NestedMessage', - filename='some/filename/some.proto', + filename=None, + file=self.my_file, containing_type=None, fields=[ descriptor.FieldDescriptor( @@ -61,7 +76,7 @@ class DescriptorTest(unittest.TestCase): full_name='protobuf_unittest.TestAllTypes.NestedMessage.bb', index=0, number=1, type=5, cpp_type=1, label=1, - default_value=0, + has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None), ], @@ -80,6 +95,7 @@ class DescriptorTest(unittest.TestCase): self.my_service = descriptor.ServiceDescriptor( name='TestServiceWithOptions', full_name='protobuf_unittest.TestServiceWithOptions', + file=self.my_file, index=0, methods=[ self.my_method @@ -109,5 +125,210 @@ class DescriptorTest(unittest.TestCase): self.assertEqual(self.my_service.GetOptions(), descriptor_pb2.ServiceOptions()) + def testFileDescriptorReferences(self): + self.assertEqual(self.my_enum.file, self.my_file) + self.assertEqual(self.my_message.file, self.my_file) + + def testFileDescriptor(self): + self.assertEqual(self.my_file.name, 'some/filename/some.proto') + self.assertEqual(self.my_file.package, 'protobuf_unittest') + + +class DescriptorCopyToProtoTest(unittest.TestCase): + """Tests for CopyTo functions of Descriptor.""" + + def _AssertProtoEqual(self, actual_proto, expected_class, expected_ascii): + expected_proto = expected_class() + text_format.Merge(expected_ascii, expected_proto) + + self.assertEqual( + actual_proto, expected_proto, + 'Not equal,\nActual:\n%s\nExpected:\n%s\n' + % (str(actual_proto), str(expected_proto))) + + def _InternalTestCopyToProto(self, desc, expected_proto_class, + expected_proto_ascii): + actual = expected_proto_class() + desc.CopyToProto(actual) + self._AssertProtoEqual( + actual, expected_proto_class, expected_proto_ascii) + + def testCopyToProto_EmptyMessage(self): + self._InternalTestCopyToProto( + unittest_pb2.TestEmptyMessage.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII) + + def testCopyToProto_NestedMessage(self): + TEST_NESTED_MESSAGE_ASCII = """ + name: 'NestedMessage' + field: < + name: 'bb' + number: 1 + label: 1 # Optional + type: 5 # TYPE_INT32 + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_NESTED_MESSAGE_ASCII) + + def testCopyToProto_ForeignNestedMessage(self): + TEST_FOREIGN_NESTED_ASCII = """ + name: 'TestForeignNested' + field: < + name: 'foreign_nested' + number: 1 + label: 1 # Optional + type: 11 # TYPE_MESSAGE + type_name: '.protobuf_unittest.TestAllTypes.NestedMessage' + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestForeignNested.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_FOREIGN_NESTED_ASCII) + + def testCopyToProto_ForeignEnum(self): + TEST_FOREIGN_ENUM_ASCII = """ + name: 'ForeignEnum' + value: < + name: 'FOREIGN_FOO' + number: 4 + > + value: < + name: 'FOREIGN_BAR' + number: 5 + > + value: < + name: 'FOREIGN_BAZ' + number: 6 + > + """ + + self._InternalTestCopyToProto( + unittest_pb2._FOREIGNENUM, + descriptor_pb2.EnumDescriptorProto, + TEST_FOREIGN_ENUM_ASCII) + + def testCopyToProto_Options(self): + TEST_DEPRECATED_FIELDS_ASCII = """ + name: 'TestDeprecatedFields' + field: < + name: 'deprecated_int32' + number: 1 + label: 1 # Optional + type: 5 # TYPE_INT32 + options: < + deprecated: true + > + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestDeprecatedFields.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_DEPRECATED_FIELDS_ASCII) + + def testCopyToProto_AllExtensions(self): + TEST_EMPTY_MESSAGE_WITH_EXTENSIONS_ASCII = """ + name: 'TestEmptyMessageWithExtensions' + extension_range: < + start: 1 + end: 536870912 + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestEmptyMessageWithExtensions.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_EMPTY_MESSAGE_WITH_EXTENSIONS_ASCII) + + def testCopyToProto_SeveralExtensions(self): + TEST_MESSAGE_WITH_SEVERAL_EXTENSIONS_ASCII = """ + name: 'TestMultipleExtensionRanges' + extension_range: < + start: 42 + end: 43 + > + extension_range: < + start: 4143 + end: 4244 + > + extension_range: < + start: 65536 + end: 536870912 + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR, + descriptor_pb2.DescriptorProto, + TEST_MESSAGE_WITH_SEVERAL_EXTENSIONS_ASCII) + + def testCopyToProto_FileDescriptor(self): + UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII = (""" + name: 'google/protobuf/unittest_import.proto' + package: 'protobuf_unittest_import' + message_type: < + name: 'ImportMessage' + field: < + name: 'd' + number: 1 + label: 1 # Optional + type: 5 # TYPE_INT32 + > + > + """ + + """enum_type: < + name: 'ImportEnum' + value: < + name: 'IMPORT_FOO' + number: 7 + > + value: < + name: 'IMPORT_BAR' + number: 8 + > + value: < + name: 'IMPORT_BAZ' + number: 9 + > + > + options: < + java_package: 'com.google.protobuf.test' + optimize_for: 1 # SPEED + > + """) + + self._InternalTestCopyToProto( + unittest_import_pb2.DESCRIPTOR, + descriptor_pb2.FileDescriptorProto, + UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII) + + def testCopyToProto_ServiceDescriptor(self): + TEST_SERVICE_ASCII = """ + name: 'TestService' + method: < + name: 'Foo' + input_type: '.protobuf_unittest.FooRequest' + output_type: '.protobuf_unittest.FooResponse' + > + method: < + name: 'Bar' + input_type: '.protobuf_unittest.BarRequest' + output_type: '.protobuf_unittest.BarResponse' + > + """ + + self._InternalTestCopyToProto( + unittest_pb2.TestService.DESCRIPTOR, + descriptor_pb2.ServiceDescriptorProto, + TEST_SERVICE_ASCII) + + if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py index 3ec3b2b1..aa05d5b3 100755 --- a/python/google/protobuf/internal/encoder.py +++ b/python/google/protobuf/internal/encoder.py @@ -28,253 +28,659 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Class for encoding protocol message primitives. +"""Code for encoding protocol message primitives. Contains the logic for encoding every logical protocol field type into one of the 5 physical wire types. + +This code is designed to push the Python interpreter's performance to the +limits. + +The basic idea is that at startup time, for every field (i.e. every +FieldDescriptor) we construct two functions: a "sizer" and an "encoder". The +sizer takes a value of this field's type and computes its byte size. The +encoder takes a writer function and a value. It encodes the value into byte +strings and invokes the writer function to write those strings. Typically the +writer function is the write() method of a cStringIO. + +We try to do as much work as possible when constructing the writer and the +sizer rather than when calling them. In particular: +* We copy any needed global functions to local variables, so that we do not need + to do costly global table lookups at runtime. +* Similarly, we try to do any attribute lookups at startup time if possible. +* Every field's tag is encoded to bytes at startup, since it can't change at + runtime. +* Whatever component of the field size we can compute at startup, we do. +* We *avoid* sharing code if doing so would make the code slower and not sharing + does not burden us too much. For example, encoders for repeated fields do + not just call the encoders for singular fields in a loop because this would + add an extra function call overhead for every loop iteration; instead, we + manually inline the single-value encoder into the loop. +* If a Python function lacks a return statement, Python actually generates + instructions to pop the result of the last statement off the stack, push + None onto the stack, and then return that. If we really don't care what + value is returned, then we can save two instructions by returning the + result of the last statement. It looks funny but it helps. +* We assume that type and bounds checking has happened at a higher level. """ -__author__ = 'robinson@google.com (Will Robinson)' +__author__ = 'kenton@google.com (Kenton Varda)' import struct -from google.protobuf import message from google.protobuf.internal import wire_format -from google.protobuf.internal import output_stream - - -# Note that much of this code is ported from //net/proto/ProtocolBuffer, and -# that the interface is strongly inspired by WireFormat from the C++ proto2 -# implementation. - - -class Encoder(object): - - """Encodes logical protocol buffer fields to the wire format.""" - - def __init__(self): - self._stream = output_stream.OutputStream() - - def ToString(self): - """Returns all values encoded in this object as a string.""" - return self._stream.ToString() - - # Append*NoTag methods. These are necessary for serializing packed - # repeated fields. The Append*() methods call these methods to do - # the actual serialization. - def AppendInt32NoTag(self, value): - """Appends a 32-bit integer to our buffer, varint-encoded.""" - self._stream.AppendVarint32(value) - - def AppendInt64NoTag(self, value): - """Appends a 64-bit integer to our buffer, varint-encoded.""" - self._stream.AppendVarint64(value) - - def AppendUInt32NoTag(self, unsigned_value): - """Appends an unsigned 32-bit integer to our buffer, varint-encoded.""" - self._stream.AppendVarUInt32(unsigned_value) - - def AppendUInt64NoTag(self, unsigned_value): - """Appends an unsigned 64-bit integer to our buffer, varint-encoded.""" - self._stream.AppendVarUInt64(unsigned_value) - - def AppendSInt32NoTag(self, value): - """Appends a 32-bit integer to our buffer, zigzag-encoded and then - varint-encoded. - """ - zigzag_value = wire_format.ZigZagEncode(value) - self._stream.AppendVarUInt32(zigzag_value) - - def AppendSInt64NoTag(self, value): - """Appends a 64-bit integer to our buffer, zigzag-encoded and then - varint-encoded. - """ - zigzag_value = wire_format.ZigZagEncode(value) - self._stream.AppendVarUInt64(zigzag_value) - - def AppendFixed32NoTag(self, unsigned_value): - """Appends an unsigned 32-bit integer to our buffer, in little-endian - byte-order. - """ - self._stream.AppendLittleEndian32(unsigned_value) - - def AppendFixed64NoTag(self, unsigned_value): - """Appends an unsigned 64-bit integer to our buffer, in little-endian - byte-order. - """ - self._stream.AppendLittleEndian64(unsigned_value) - - def AppendSFixed32NoTag(self, value): - """Appends a signed 32-bit integer to our buffer, in little-endian - byte-order. - """ - sign = (value & 0x80000000) and -1 or 0 - if value >> 32 != sign: - raise message.EncodeError('SFixed32 out of range: %d' % value) - self._stream.AppendLittleEndian32(value & 0xffffffff) - - def AppendSFixed64NoTag(self, value): - """Appends a signed 64-bit integer to our buffer, in little-endian - byte-order. - """ - sign = (value & 0x8000000000000000) and -1 or 0 - if value >> 64 != sign: - raise message.EncodeError('SFixed64 out of range: %d' % value) - self._stream.AppendLittleEndian64(value & 0xffffffffffffffff) - - def AppendFloatNoTag(self, value): - """Appends a floating-point number to our buffer.""" - 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(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, value)) - - def AppendBoolNoTag(self, value): - """Appends a boolean to our buffer.""" - self.AppendInt32NoTag(value) - - def AppendEnumNoTag(self, value): - """Appends an enum value to our buffer.""" - self.AppendInt32NoTag(value) - - - # All the Append*() methods below first append a tag+type pair to the buffer - # before appending the specified value. - - def AppendInt32(self, field_number, value): - """Appends a 32-bit integer to our buffer, varint-encoded.""" - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendInt32NoTag(value) - - def AppendInt64(self, field_number, value): - """Appends a 64-bit integer to our buffer, varint-encoded.""" - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendInt64NoTag(value) - - def AppendUInt32(self, field_number, unsigned_value): - """Appends an unsigned 32-bit integer to our buffer, varint-encoded.""" - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendUInt32NoTag(unsigned_value) - - def AppendUInt64(self, field_number, unsigned_value): - """Appends an unsigned 64-bit integer to our buffer, varint-encoded.""" - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendUInt64NoTag(unsigned_value) - - def AppendSInt32(self, field_number, value): - """Appends a 32-bit integer to our buffer, zigzag-encoded and then - varint-encoded. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendSInt32NoTag(value) - - def AppendSInt64(self, field_number, value): - """Appends a 64-bit integer to our buffer, zigzag-encoded and then - varint-encoded. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) - self.AppendSInt64NoTag(value) - - def AppendFixed32(self, field_number, unsigned_value): - """Appends an unsigned 32-bit integer to our buffer, in little-endian - byte-order. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) - self.AppendFixed32NoTag(unsigned_value) - - def AppendFixed64(self, field_number, unsigned_value): - """Appends an unsigned 64-bit integer to our buffer, in little-endian - byte-order. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) - self.AppendFixed64NoTag(unsigned_value) - - def AppendSFixed32(self, field_number, value): - """Appends a signed 32-bit integer to our buffer, in little-endian - byte-order. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) - self.AppendSFixed32NoTag(value) - - def AppendSFixed64(self, field_number, value): - """Appends a signed 64-bit integer to our buffer, in little-endian - byte-order. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) - self.AppendSFixed64NoTag(value) - - def AppendFloat(self, field_number, value): - """Appends a floating-point number to our buffer.""" - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) - self.AppendFloatNoTag(value) - - def AppendDouble(self, field_number, value): - """Appends a double-precision floating-point number to our buffer.""" - self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) - self.AppendDoubleNoTag(value) - - def AppendBool(self, field_number, value): - """Appends a boolean to our buffer.""" - self.AppendInt32(field_number, value) - - def AppendEnum(self, field_number, value): - """Appends an enum value to our buffer.""" - self.AppendInt32(field_number, value) - - def AppendString(self, field_number, value): - """Appends a length-prefixed unicode string, encoded as UTF-8 to our buffer, - with the length varint-encoded. - """ - self.AppendBytes(field_number, value.encode('utf-8')) - - def AppendBytes(self, field_number, value): - """Appends a length-prefixed sequence of bytes to our buffer, with the - length varint-encoded. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - self._stream.AppendVarUInt32(len(value)) - self._stream.AppendRawBytes(value) - - # TODO(robinson): For AppendGroup() and AppendMessage(), we'd really like to - # avoid the extra string copy here. We can do so if we widen the Message - # interface to be able to serialize to a stream in addition to a string. The - # challenge when thinking ahead to the Python/C API implementation of Message - # is finding a stream-like Python thing to which we can write raw bytes - # from C. I'm not sure such a thing exists(?). (array.array is pretty much - # what we want, but it's not directly exposed in the Python/C API). - - def AppendGroup(self, field_number, group): - """Appends a group to our buffer. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_START_GROUP) - self._stream.AppendRawBytes(group.SerializeToString()) - self.AppendTag(field_number, wire_format.WIRETYPE_END_GROUP) - - def AppendMessage(self, field_number, msg): - """Appends a nested message to our buffer. - """ - self.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - self._stream.AppendVarUInt32(msg.ByteSize()) - self._stream.AppendRawBytes(msg.SerializeToString()) - - def AppendMessageSetItem(self, field_number, msg): - """Appends an item using the message set wire format. - - The message set message looks like this: - message MessageSet { - repeated group Item = 1 { - required int32 type_id = 2; - required string message = 3; - } + + +def _VarintSize(value): + """Compute the size of a varint value.""" + if value <= 0x7f: return 1 + if value <= 0x3fff: return 2 + if value <= 0x1fffff: return 3 + if value <= 0xfffffff: return 4 + if value <= 0x7ffffffff: return 5 + if value <= 0x3ffffffffff: return 6 + if value <= 0x1ffffffffffff: return 7 + if value <= 0xffffffffffffff: return 8 + if value <= 0x7fffffffffffffff: return 9 + return 10 + + +def _SignedVarintSize(value): + """Compute the size of a signed varint value.""" + if value < 0: return 10 + if value <= 0x7f: return 1 + if value <= 0x3fff: return 2 + if value <= 0x1fffff: return 3 + if value <= 0xfffffff: return 4 + if value <= 0x7ffffffff: return 5 + if value <= 0x3ffffffffff: return 6 + if value <= 0x1ffffffffffff: return 7 + if value <= 0xffffffffffffff: return 8 + if value <= 0x7fffffffffffffff: return 9 + return 10 + + +def _TagSize(field_number): + """Returns the number of bytes required to serialize a tag with this field + number.""" + # Just pass in type 0, since the type won't affect the tag+type size. + return _VarintSize(wire_format.PackTag(field_number, 0)) + + +# -------------------------------------------------------------------- +# In this section we define some generic sizers. Each of these functions +# takes parameters specific to a particular field type, e.g. int32 or fixed64. +# It returns another function which in turn takes parameters specific to a +# particular field, e.g. the field number and whether it is repeated or packed. +# Look at the next section to see how these are used. + + +def _SimpleSizer(compute_value_size): + """A sizer which uses the function compute_value_size to compute the size of + each value. Typically compute_value_size is _VarintSize.""" + + def SpecificSizer(field_number, is_repeated, is_packed): + tag_size = _TagSize(field_number) + if is_packed: + local_VarintSize = _VarintSize + def PackedFieldSize(value): + result = 0 + for element in value: + result += compute_value_size(element) + return result + local_VarintSize(result) + tag_size + return PackedFieldSize + elif is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + result += compute_value_size(element) + return result + return RepeatedFieldSize + else: + def FieldSize(value): + return tag_size + compute_value_size(value) + return FieldSize + + return SpecificSizer + + +def _ModifiedSizer(compute_value_size, modify_value): + """Like SimpleSizer, but modify_value is invoked on each value before it is + passed to compute_value_size. modify_value is typically ZigZagEncode.""" + + def SpecificSizer(field_number, is_repeated, is_packed): + tag_size = _TagSize(field_number) + if is_packed: + local_VarintSize = _VarintSize + def PackedFieldSize(value): + result = 0 + for element in value: + result += compute_value_size(modify_value(element)) + return result + local_VarintSize(result) + tag_size + return PackedFieldSize + elif is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + result += compute_value_size(modify_value(element)) + return result + return RepeatedFieldSize + else: + def FieldSize(value): + return tag_size + compute_value_size(modify_value(value)) + return FieldSize + + return SpecificSizer + + +def _FixedSizer(value_size): + """Like _SimpleSizer except for a fixed-size field. The input is the size + of one value.""" + + def SpecificSizer(field_number, is_repeated, is_packed): + tag_size = _TagSize(field_number) + if is_packed: + local_VarintSize = _VarintSize + def PackedFieldSize(value): + result = len(value) * value_size + return result + local_VarintSize(result) + tag_size + return PackedFieldSize + elif is_repeated: + element_size = value_size + tag_size + def RepeatedFieldSize(value): + return len(value) * element_size + return RepeatedFieldSize + else: + field_size = value_size + tag_size + def FieldSize(value): + return field_size + return FieldSize + + return SpecificSizer + + +# ==================================================================== +# Here we declare a sizer constructor for each field type. Each "sizer +# constructor" is a function that takes (field_number, is_repeated, is_packed) +# as parameters and returns a sizer, which in turn takes a field value as +# a parameter and returns its encoded size. + + +Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize) + +UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize) + +SInt32Sizer = SInt64Sizer = _ModifiedSizer( + _SignedVarintSize, wire_format.ZigZagEncode) + +Fixed32Sizer = SFixed32Sizer = FloatSizer = _FixedSizer(4) +Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8) + +BoolSizer = _FixedSizer(1) + + +def StringSizer(field_number, is_repeated, is_packed): + """Returns a sizer for a string field.""" + + tag_size = _TagSize(field_number) + local_VarintSize = _VarintSize + local_len = len + assert not is_packed + if is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + l = local_len(element.encode('utf-8')) + result += local_VarintSize(l) + l + return result + return RepeatedFieldSize + else: + def FieldSize(value): + l = local_len(value.encode('utf-8')) + return tag_size + local_VarintSize(l) + l + return FieldSize + + +def BytesSizer(field_number, is_repeated, is_packed): + """Returns a sizer for a bytes field.""" + + tag_size = _TagSize(field_number) + local_VarintSize = _VarintSize + local_len = len + assert not is_packed + if is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + l = local_len(element) + result += local_VarintSize(l) + l + return result + return RepeatedFieldSize + else: + def FieldSize(value): + l = local_len(value) + return tag_size + local_VarintSize(l) + l + return FieldSize + + +def GroupSizer(field_number, is_repeated, is_packed): + """Returns a sizer for a group field.""" + + tag_size = _TagSize(field_number) * 2 + assert not is_packed + if is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + result += element.ByteSize() + return result + return RepeatedFieldSize + else: + def FieldSize(value): + return tag_size + value.ByteSize() + return FieldSize + + +def MessageSizer(field_number, is_repeated, is_packed): + """Returns a sizer for a message field.""" + + tag_size = _TagSize(field_number) + local_VarintSize = _VarintSize + assert not is_packed + if is_repeated: + def RepeatedFieldSize(value): + result = tag_size * len(value) + for element in value: + l = element.ByteSize() + result += local_VarintSize(l) + l + return result + return RepeatedFieldSize + else: + def FieldSize(value): + l = value.ByteSize() + return tag_size + local_VarintSize(l) + l + return FieldSize + + +# -------------------------------------------------------------------- +# MessageSet is special. + + +def MessageSetItemSizer(field_number): + """Returns a sizer for extensions of MessageSet. + + The message set message looks like this: + message MessageSet { + repeated group Item = 1 { + required int32 type_id = 2; + required string message = 3; + } + } + """ + static_size = (_TagSize(1) * 2 + _TagSize(2) + _VarintSize(field_number) + + _TagSize(3)) + local_VarintSize = _VarintSize + + def FieldSize(value): + l = value.ByteSize() + return static_size + local_VarintSize(l) + l + + return FieldSize + + +# ==================================================================== +# Encoders! + + +def _VarintEncoder(): + """Return an encoder for a basic varint value (does not include tag).""" + + local_chr = chr + def EncodeVarint(write, value): + bits = value & 0x7f + value >>= 7 + while value: + write(local_chr(0x80|bits)) + bits = value & 0x7f + value >>= 7 + return write(local_chr(bits)) + + return EncodeVarint + + +def _SignedVarintEncoder(): + """Return an encoder for a basic signed varint value (does not include + tag).""" + + local_chr = chr + def EncodeSignedVarint(write, value): + if value < 0: + value += (1 << 64) + bits = value & 0x7f + value >>= 7 + while value: + write(local_chr(0x80|bits)) + bits = value & 0x7f + value >>= 7 + return write(local_chr(bits)) + + return EncodeSignedVarint + + +_EncodeVarint = _VarintEncoder() +_EncodeSignedVarint = _SignedVarintEncoder() + + +def _VarintBytes(value): + """Encode the given integer as a varint and return the bytes. This is only + called at startup time so it doesn't need to be fast.""" + + pieces = [] + _EncodeVarint(pieces.append, value) + return "".join(pieces) + + +def TagBytes(field_number, wire_type): + """Encode the given tag and return the bytes. Only called at startup.""" + + return _VarintBytes(wire_format.PackTag(field_number, wire_type)) + +# -------------------------------------------------------------------- +# As with sizers (see above), we have a number of common encoder +# implementations. + + +def _SimpleEncoder(wire_type, encode_value, compute_value_size): + """Return a constructor for an encoder for fields of a particular type. + + Args: + wire_type: The field's wire type, for encoding tags. + encode_value: A function which encodes an individual value, e.g. + _EncodeVarint(). + compute_value_size: A function which computes the size of an individual + value, e.g. _VarintSize(). + """ + + def SpecificEncoder(field_number, is_repeated, is_packed): + if is_packed: + tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + local_EncodeVarint = _EncodeVarint + def EncodePackedField(write, value): + write(tag_bytes) + size = 0 + for element in value: + size += compute_value_size(element) + local_EncodeVarint(write, size) + for element in value: + encode_value(write, element) + return EncodePackedField + elif is_repeated: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeRepeatedField(write, value): + for element in value: + write(tag_bytes) + encode_value(write, element) + return EncodeRepeatedField + else: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeField(write, value): + write(tag_bytes) + return encode_value(write, value) + return EncodeField + + return SpecificEncoder + + +def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value): + """Like SimpleEncoder but additionally invokes modify_value on every value + before passing it to encode_value. Usually modify_value is ZigZagEncode.""" + + def SpecificEncoder(field_number, is_repeated, is_packed): + if is_packed: + tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + local_EncodeVarint = _EncodeVarint + def EncodePackedField(write, value): + write(tag_bytes) + size = 0 + for element in value: + size += compute_value_size(modify_value(element)) + local_EncodeVarint(write, size) + for element in value: + encode_value(write, modify_value(element)) + return EncodePackedField + elif is_repeated: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeRepeatedField(write, value): + for element in value: + write(tag_bytes) + encode_value(write, modify_value(element)) + return EncodeRepeatedField + else: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeField(write, value): + write(tag_bytes) + return encode_value(write, modify_value(value)) + return EncodeField + + return SpecificEncoder + + +def _StructPackEncoder(wire_type, format): + """Return a constructor for an encoder for a fixed-width field. + + Args: + wire_type: The field's wire type, for encoding tags. + format: The format string to pass to struct.pack(). + """ + + value_size = struct.calcsize(format) + + def SpecificEncoder(field_number, is_repeated, is_packed): + local_struct_pack = struct.pack + if is_packed: + tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + local_EncodeVarint = _EncodeVarint + def EncodePackedField(write, value): + write(tag_bytes) + local_EncodeVarint(write, len(value) * value_size) + for element in value: + write(local_struct_pack(format, element)) + return EncodePackedField + elif is_repeated: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeRepeatedField(write, value): + for element in value: + write(tag_bytes) + write(local_struct_pack(format, element)) + return EncodeRepeatedField + else: + tag_bytes = TagBytes(field_number, wire_type) + def EncodeField(write, value): + write(tag_bytes) + return write(local_struct_pack(format, value)) + return EncodeField + + return SpecificEncoder + + +# ==================================================================== +# Here we declare an encoder constructor for each field type. These work +# very similarly to sizer constructors, described earlier. + + +Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder( + wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize) + +UInt32Encoder = UInt64Encoder = _SimpleEncoder( + wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize) + +SInt32Encoder = SInt64Encoder = _ModifiedEncoder( + wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize, + wire_format.ZigZagEncode) + +# Note that Python conveniently guarantees that when using the '<' prefix on +# formats, they will also have the same size across all platforms (as opposed +# to without the prefix, where their sizes depend on the C compiler's basic +# type sizes). +Fixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '= len(set(t[1] for t in scalar_tests))) - for args in scalar_tests: - self.AppendScalarTestHelper(*args) - - def testAppendScalarsWithoutTags(self): - scalar_no_tag_tests = [ - ['int32', self.encoder.AppendInt32NoTag, 'AppendVarint32', None, 0], - ['int64', self.encoder.AppendInt64NoTag, 'AppendVarint64', None, 0], - ['uint32', self.encoder.AppendUInt32NoTag, 'AppendVarUInt32', None, 0], - ['uint64', self.encoder.AppendUInt64NoTag, 'AppendVarUInt64', None, 0], - ['fixed32', self.encoder.AppendFixed32NoTag, - 'AppendLittleEndian32', None, 0], - ['fixed64', self.encoder.AppendFixed64NoTag, - 'AppendLittleEndian64', None, 0], - ['sfixed32', self.encoder.AppendSFixed32NoTag, - 'AppendLittleEndian32', None, 0], - ['sfixed64', self.encoder.AppendSFixed64NoTag, - 'AppendLittleEndian64', None, 0], - ['float', self.encoder.AppendFloatNoTag, - 'AppendRawBytes', None, self.VAL, self.LITTLE_FLOAT_VAL], - ['double', self.encoder.AppendDoubleNoTag, - '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, - 'AppendVarUInt32', None, -1, 1], - ['sint64', self.encoder.AppendSInt64NoTag, - 'AppendVarUInt64', None, -1, 1], - ] - - self.assertEqual(len(scalar_no_tag_tests), - len(set(t[0] for t in scalar_no_tag_tests))) - self.assert_(len(scalar_no_tag_tests) >= - len(set(t[1] for t in scalar_no_tag_tests))) - for args in scalar_no_tag_tests: - # For no tag tests, the wire_type is not used, so we put in None. - self.AppendScalarTestHelper(is_tag_test=False, *args) - - def testAppendGroup(self): - field_number = 23 - # Should first append the start-group marker. - self.mock_stream.AppendVarUInt32( - self.PackTag(field_number, wire_format.WIRETYPE_START_GROUP)) - # Should then serialize itself. - self.mock_message.SerializeToString().AndReturn('foo') - self.mock_stream.AppendRawBytes('foo') - # Should finally append the end-group marker. - self.mock_stream.AppendVarUInt32( - self.PackTag(field_number, wire_format.WIRETYPE_END_GROUP)) - - self.mox.ReplayAll() - self.encoder.AppendGroup(field_number, self.mock_message) - self.mox.VerifyAll() - - def testAppendMessage(self): - field_number = 23 - byte_size = 42 - # Should first append the field number and type information. - self.mock_stream.AppendVarUInt32( - self.PackTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)) - # Should then append its length. - self.mock_message.ByteSize().AndReturn(byte_size) - self.mock_stream.AppendVarUInt32(byte_size) - # Should then serialize itself to the encoder. - self.mock_message.SerializeToString().AndReturn('foo') - self.mock_stream.AppendRawBytes('foo') - - self.mox.ReplayAll() - self.encoder.AppendMessage(field_number, self.mock_message) - self.mox.VerifyAll() - - def testAppendMessageSetItem(self): - field_number = 23 - byte_size = 42 - # Should first append the field number and type information. - self.mock_stream.AppendVarUInt32( - self.PackTag(1, wire_format.WIRETYPE_START_GROUP)) - self.mock_stream.AppendVarUInt32( - self.PackTag(2, wire_format.WIRETYPE_VARINT)) - self.mock_stream.AppendVarint32(field_number) - self.mock_stream.AppendVarUInt32( - self.PackTag(3, wire_format.WIRETYPE_LENGTH_DELIMITED)) - # Should then append its length. - self.mock_message.ByteSize().AndReturn(byte_size) - self.mock_stream.AppendVarUInt32(byte_size) - # Should then serialize itself to the encoder. - self.mock_message.SerializeToString().AndReturn('foo') - self.mock_stream.AppendRawBytes('foo') - self.mock_stream.AppendVarUInt32( - self.PackTag(1, wire_format.WIRETYPE_END_GROUP)) - - self.mox.ReplayAll() - self.encoder.AppendMessageSetItem(field_number, self.mock_message) - self.mox.VerifyAll() - - def testAppendSFixed(self): - # Most of our bounds-checking is done in output_stream.py, - # but encoder.py is responsible for transforming signed - # fixed-width integers into unsigned ones, so we test here - # to ensure that we're not losing any entropy when we do - # that conversion. - field_number = 10 - self.assertRaises(message.EncodeError, self.encoder.AppendSFixed32, - 10, wire_format.UINT32_MAX + 1) - self.assertRaises(message.EncodeError, self.encoder.AppendSFixed32, - 10, -(1 << 32)) - self.assertRaises(message.EncodeError, self.encoder.AppendSFixed64, - 10, wire_format.UINT64_MAX + 1) - self.assertRaises(message.EncodeError, self.encoder.AppendSFixed64, - 10, -(1 << 64)) - - -if __name__ == '__main__': - unittest.main() diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 11fcfa0c..dd27c9a3 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -35,15 +35,20 @@ # indirect testing of the protocol compiler output. """Unittest that directly tests the output of the pure-Python protocol -compiler. See //net/proto2/internal/reflection_test.py for a test which +compiler. See //google/protobuf/reflection_test.py for a test which further ensures that we can use Python protocol message objects as we expect. """ __author__ = 'robinson@google.com (Will Robinson)' import unittest +from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 +from google.protobuf import unittest_no_generic_services_pb2 + + +MAX_EXTENSION = 536870912 class GeneratorTest(unittest.TestCase): @@ -71,6 +76,31 @@ class GeneratorTest(unittest.TestCase): self.assertEqual(3, proto.BAZ) self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ) + def testExtremeDefaultValues(self): + message = unittest_pb2.TestExtremeDefaultValues() + self.assertEquals(float('inf'), message.inf_double) + self.assertEquals(float('-inf'), message.neg_inf_double) + self.assert_(message.nan_double != message.nan_double) + self.assertEquals(float('inf'), message.inf_float) + self.assertEquals(float('-inf'), message.neg_inf_float) + self.assert_(message.nan_float != message.nan_float) + + def testHasDefaultValues(self): + desc = unittest_pb2.TestAllTypes.DESCRIPTOR + + expected_has_default_by_name = { + 'optional_int32': False, + 'repeated_int32': False, + 'optional_nested_message': False, + 'default_int32': True, + } + + has_default_by_name = dict( + [(f.name, f.has_default_value) + for f in desc.fields + if f.name in expected_has_default_by_name]) + self.assertEqual(expected_has_default_by_name, has_default_by_name) + def testContainingTypeBehaviorForExtensions(self): self.assertEqual(unittest_pb2.optional_int32_extension.containing_type, unittest_pb2.TestAllExtensions.DESCRIPTOR) @@ -95,6 +125,81 @@ class GeneratorTest(unittest.TestCase): proto = unittest_mset_pb2.TestMessageSet() self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format) + def testNestedTypes(self): + self.assertEquals( + set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types), + set([ + unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR, + unittest_pb2.TestAllTypes.OptionalGroup.DESCRIPTOR, + unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR, + ])) + self.assertEqual(unittest_pb2.TestEmptyMessage.DESCRIPTOR.nested_types, []) + self.assertEqual( + unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.nested_types, []) + + def testContainingType(self): + self.assertTrue( + unittest_pb2.TestEmptyMessage.DESCRIPTOR.containing_type is None) + self.assertTrue( + unittest_pb2.TestAllTypes.DESCRIPTOR.containing_type is None) + self.assertEqual( + unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, + unittest_pb2.TestAllTypes.DESCRIPTOR) + self.assertEqual( + unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, + unittest_pb2.TestAllTypes.DESCRIPTOR) + self.assertEqual( + unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR.containing_type, + unittest_pb2.TestAllTypes.DESCRIPTOR) + + def testContainingTypeInEnumDescriptor(self): + self.assertTrue(unittest_pb2._FOREIGNENUM.containing_type is None) + self.assertEqual(unittest_pb2._TESTALLTYPES_NESTEDENUM.containing_type, + unittest_pb2.TestAllTypes.DESCRIPTOR) + + def testPackage(self): + self.assertEqual( + unittest_pb2.TestAllTypes.DESCRIPTOR.file.package, + 'protobuf_unittest') + desc = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR + self.assertEqual(desc.file.package, 'protobuf_unittest') + self.assertEqual( + unittest_import_pb2.ImportMessage.DESCRIPTOR.file.package, + 'protobuf_unittest_import') + + self.assertEqual( + unittest_pb2._FOREIGNENUM.file.package, 'protobuf_unittest') + self.assertEqual( + unittest_pb2._TESTALLTYPES_NESTEDENUM.file.package, + 'protobuf_unittest') + self.assertEqual( + unittest_import_pb2._IMPORTENUM.file.package, + 'protobuf_unittest_import') + + def testExtensionRange(self): + self.assertEqual( + unittest_pb2.TestAllTypes.DESCRIPTOR.extension_ranges, []) + self.assertEqual( + unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges, + [(1, MAX_EXTENSION)]) + self.assertEqual( + unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges, + [(42, 43), (4143, 4244), (65536, MAX_EXTENSION)]) + + def testFileDescriptor(self): + self.assertEqual(unittest_pb2.DESCRIPTOR.name, + 'google/protobuf/unittest.proto') + self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest') + self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None) + + def testNoGenericServices(self): + # unittest_no_generic_services.proto should contain defs for everything + # except services. + self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage")) + self.assertTrue(hasattr(unittest_no_generic_services_pb2, "FOO")) + self.assertTrue(hasattr(unittest_no_generic_services_pb2, "test_extension")) + self.assertFalse(hasattr(unittest_no_generic_services_pb2, "TestService")) + if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/input_stream.py b/python/google/protobuf/internal/input_stream.py deleted file mode 100755 index 7bda17e3..00000000 --- a/python/google/protobuf/internal/input_stream.py +++ /dev/null @@ -1,338 +0,0 @@ -# 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. - -"""InputStream is the primitive interface for reading bits from the wire. - -All protocol buffer deserialization can be expressed in terms of -the InputStream primitives provided here. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import array -import struct -from google.protobuf import message -from google.protobuf.internal import wire_format - - -# Note that much of this code is ported from //net/proto/ProtocolBuffer, and -# that the interface is strongly inspired by CodedInputStream from the C++ -# proto2 implementation. - - -class InputStreamBuffer(object): - - """Contains all logic for reading bits, and dealing with stream position. - - If an InputStream method ever raises an exception, the stream is left - in an indeterminate state and is not safe for further use. - """ - - def __init__(self, s): - # What we really want is something like array('B', s), where elements we - # read from the array are already given to us as one-byte integers. BUT - # using array() instead of buffer() would force full string copies to result - # from each GetSubBuffer() call. - # - # So, if the N serialized bytes of a single protocol buffer object are - # split evenly between 2 child messages, and so on recursively, using - # array('B', s) instead of buffer() would incur an additional N*logN bytes - # copied during deserialization. - # - # The higher constant overhead of having to ord() for every byte we read - # from the buffer in _ReadVarintHelper() could definitely lead to worse - # performance in many real-world scenarios, even if the asymptotic - # complexity is better. However, our real answer is that the mythical - # Python/C extension module output mode for the protocol compiler will - # be blazing-fast and will eliminate most use of this class anyway. - self._buffer = buffer(s) - self._pos = 0 - - def EndOfStream(self): - """Returns true iff we're at the end of the stream. - If this returns true, then a call to any other InputStream method - will raise an exception. - """ - return self._pos >= len(self._buffer) - - def Position(self): - """Returns the current position in the stream, or equivalently, the - number of bytes read so far. - """ - return self._pos - - def GetSubBuffer(self, size=None): - """Returns a sequence-like object that represents a portion of our - underlying sequence. - - Position 0 in the returned object corresponds to self.Position() - in this stream. - - If size is specified, then the returned object ends after the - next "size" bytes in this stream. If size is not specified, - then the returned object ends at the end of this stream. - - We guarantee that the returned object R supports the Python buffer - interface (and thus that the call buffer(R) will work). - - Note that the returned buffer is read-only. - - The intended use for this method is for nested-message and nested-group - deserialization, where we want to make a recursive MergeFromString() - call on the portion of the original sequence that contains the serialized - nested message. (And we'd like to do so without making unnecessary string - copies). - - REQUIRES: size is nonnegative. - """ - # Note that buffer() doesn't perform any actual string copy. - if size is None: - return buffer(self._buffer, self._pos) - else: - if size < 0: - raise message.DecodeError('Negative size %d' % size) - return buffer(self._buffer, self._pos, size) - - def SkipBytes(self, num_bytes): - """Skip num_bytes bytes ahead, or go to the end of the stream, whichever - comes first. - - REQUIRES: num_bytes is nonnegative. - """ - if num_bytes < 0: - raise message.DecodeError('Negative num_bytes %d' % num_bytes) - self._pos += num_bytes - self._pos = min(self._pos, len(self._buffer)) - - def ReadBytes(self, size): - """Reads up to 'size' bytes from the stream, stopping early - only if we reach the end of the stream. Returns the bytes read - as a string. - """ - if size < 0: - raise message.DecodeError('Negative size %d' % size) - s = (self._buffer[self._pos : self._pos + size]) - self._pos += len(s) # Only advance by the number of bytes actually read. - return s - - def ReadLittleEndian32(self): - """Interprets the next 4 bytes of the stream as a little-endian - encoded, unsiged 32-bit integer, and returns that integer. - """ - try: - i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN, - self._buffer[self._pos : self._pos + 4]) - self._pos += 4 - return i[0] # unpack() result is a 1-element tuple. - except struct.error, e: - raise message.DecodeError(e) - - def ReadLittleEndian64(self): - """Interprets the next 8 bytes of the stream as a little-endian - encoded, unsiged 64-bit integer, and returns that integer. - """ - try: - i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN, - self._buffer[self._pos : self._pos + 8]) - self._pos += 8 - return i[0] # unpack() result is a 1-element tuple. - except struct.error, e: - raise message.DecodeError(e) - - def ReadVarint32(self): - """Reads a varint from the stream, interprets this varint - as a signed, 32-bit integer, and returns the integer. - """ - i = self.ReadVarint64() - if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX: - raise message.DecodeError('Value out of range for int32: %d' % i) - return int(i) - - def ReadVarUInt32(self): - """Reads a varint from the stream, interprets this varint - as an unsigned, 32-bit integer, and returns the integer. - """ - i = self.ReadVarUInt64() - if i > wire_format.UINT32_MAX: - raise message.DecodeError('Value out of range for uint32: %d' % i) - return i - - def ReadVarint64(self): - """Reads a varint from the stream, interprets this varint - as a signed, 64-bit integer, and returns the integer. - """ - i = self.ReadVarUInt64() - if i > wire_format.INT64_MAX: - i -= (1 << 64) - return i - - def ReadVarUInt64(self): - """Reads a varint from the stream, interprets this varint - as an unsigned, 64-bit integer, and returns the integer. - """ - i = self._ReadVarintHelper() - if not 0 <= i <= wire_format.UINT64_MAX: - raise message.DecodeError('Value out of range for uint64: %d' % i) - return i - - def _ReadVarintHelper(self): - """Helper for the various varint-reading methods above. - Reads an unsigned, varint-encoded integer from the stream and - returns this integer. - - Does no bounds checking except to ensure that we read at most as many bytes - as could possibly be present in a varint-encoded 64-bit number. - """ - result = 0 - shift = 0 - while 1: - if shift >= 64: - raise message.DecodeError('Too many bytes when decoding varint.') - try: - b = ord(self._buffer[self._pos]) - except IndexError: - raise message.DecodeError('Truncated varint.') - self._pos += 1 - result |= ((b & 0x7f) << shift) - shift += 7 - if not (b & 0x80): - return result - - -class InputStreamArray(object): - - """Contains all logic for reading bits, and dealing with stream position. - - If an InputStream method ever raises an exception, the stream is left - in an indeterminate state and is not safe for further use. - - This alternative to InputStreamBuffer is used in environments where buffer() - is unavailble, such as Google App Engine. - """ - - def __init__(self, s): - self._buffer = array.array('B', s) - self._pos = 0 - - def EndOfStream(self): - return self._pos >= len(self._buffer) - - def Position(self): - return self._pos - - def GetSubBuffer(self, size=None): - if size is None: - return self._buffer[self._pos : ].tostring() - else: - if size < 0: - raise message.DecodeError('Negative size %d' % size) - return self._buffer[self._pos : self._pos + size].tostring() - - def SkipBytes(self, num_bytes): - if num_bytes < 0: - raise message.DecodeError('Negative num_bytes %d' % num_bytes) - self._pos += num_bytes - self._pos = min(self._pos, len(self._buffer)) - - def ReadBytes(self, size): - if size < 0: - raise message.DecodeError('Negative size %d' % size) - s = self._buffer[self._pos : self._pos + size].tostring() - self._pos += len(s) # Only advance by the number of bytes actually read. - return s - - def ReadLittleEndian32(self): - try: - i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN, - self._buffer[self._pos : self._pos + 4]) - self._pos += 4 - return i[0] # unpack() result is a 1-element tuple. - except struct.error, e: - raise message.DecodeError(e) - - def ReadLittleEndian64(self): - try: - i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN, - self._buffer[self._pos : self._pos + 8]) - self._pos += 8 - return i[0] # unpack() result is a 1-element tuple. - except struct.error, e: - raise message.DecodeError(e) - - def ReadVarint32(self): - i = self.ReadVarint64() - if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX: - raise message.DecodeError('Value out of range for int32: %d' % i) - return int(i) - - def ReadVarUInt32(self): - i = self.ReadVarUInt64() - if i > wire_format.UINT32_MAX: - raise message.DecodeError('Value out of range for uint32: %d' % i) - return i - - def ReadVarint64(self): - i = self.ReadVarUInt64() - if i > wire_format.INT64_MAX: - i -= (1 << 64) - return i - - def ReadVarUInt64(self): - i = self._ReadVarintHelper() - if not 0 <= i <= wire_format.UINT64_MAX: - raise message.DecodeError('Value out of range for uint64: %d' % i) - return i - - def _ReadVarintHelper(self): - result = 0 - shift = 0 - while 1: - if shift >= 64: - raise message.DecodeError('Too many bytes when decoding varint.') - try: - b = self._buffer[self._pos] - except IndexError: - raise message.DecodeError('Truncated varint.') - self._pos += 1 - result |= ((b & 0x7f) << shift) - shift += 7 - if not (b & 0x80): - return result - - -try: - buffer('') - InputStream = InputStreamBuffer -except NotImplementedError: - # Google App Engine: dev_appserver.py - InputStream = InputStreamArray -except RuntimeError: - # Google App Engine: production - InputStream = InputStreamArray diff --git a/python/google/protobuf/internal/input_stream_test.py b/python/google/protobuf/internal/input_stream_test.py deleted file mode 100755 index ecec7f7d..00000000 --- a/python/google/protobuf/internal/input_stream_test.py +++ /dev/null @@ -1,314 +0,0 @@ -#! /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. - -"""Test for google.protobuf.internal.input_stream.""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import unittest -from google.protobuf import message -from google.protobuf.internal import wire_format -from google.protobuf.internal import input_stream - - -class InputStreamBufferTest(unittest.TestCase): - - def setUp(self): - self.__original_input_stream = input_stream.InputStream - input_stream.InputStream = input_stream.InputStreamBuffer - - def tearDown(self): - input_stream.InputStream = self.__original_input_stream - - def testEndOfStream(self): - stream = input_stream.InputStream('abcd') - self.assertFalse(stream.EndOfStream()) - self.assertEqual('abcd', stream.ReadBytes(10)) - self.assertTrue(stream.EndOfStream()) - - def testPosition(self): - stream = input_stream.InputStream('abcd') - self.assertEqual(0, stream.Position()) - self.assertEqual(0, stream.Position()) # No side-effects. - stream.ReadBytes(1) - self.assertEqual(1, stream.Position()) - stream.ReadBytes(1) - self.assertEqual(2, stream.Position()) - stream.ReadBytes(10) - self.assertEqual(4, stream.Position()) # Can't go past end of stream. - - def testGetSubBuffer(self): - stream = input_stream.InputStream('abcd') - # Try leaving out the size. - self.assertEqual('abcd', str(stream.GetSubBuffer())) - stream.SkipBytes(1) - # GetSubBuffer() always starts at current size. - self.assertEqual('bcd', str(stream.GetSubBuffer())) - # Try 0-size. - self.assertEqual('', str(stream.GetSubBuffer(0))) - # Negative sizes should raise an error. - self.assertRaises(message.DecodeError, stream.GetSubBuffer, -1) - # Positive sizes should work as expected. - self.assertEqual('b', str(stream.GetSubBuffer(1))) - self.assertEqual('bc', str(stream.GetSubBuffer(2))) - # Sizes longer than remaining bytes in the buffer should - # return the whole remaining buffer. - self.assertEqual('bcd', str(stream.GetSubBuffer(1000))) - - def testSkipBytes(self): - stream = input_stream.InputStream('') - # Skipping bytes when at the end of stream - # should have no effect. - stream.SkipBytes(0) - stream.SkipBytes(1) - stream.SkipBytes(2) - self.assertTrue(stream.EndOfStream()) - self.assertEqual(0, stream.Position()) - - # Try skipping within a stream. - stream = input_stream.InputStream('abcd') - self.assertEqual(0, stream.Position()) - stream.SkipBytes(1) - self.assertEqual(1, stream.Position()) - stream.SkipBytes(10) # Can't skip past the end. - self.assertEqual(4, stream.Position()) - - # Ensure that a negative skip raises an exception. - stream = input_stream.InputStream('abcd') - stream.SkipBytes(1) - self.assertRaises(message.DecodeError, stream.SkipBytes, -1) - - def testReadBytes(self): - s = 'abcd' - # Also test going past the total stream length. - for i in range(len(s) + 10): - stream = input_stream.InputStream(s) - self.assertEqual(s[:i], stream.ReadBytes(i)) - self.assertEqual(min(i, len(s)), stream.Position()) - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadBytes, -1) - - def EnsureFailureOnEmptyStream(self, input_stream_method): - """Helper for integer-parsing tests below. - Ensures that the given InputStream method raises a DecodeError - if called on a stream with no bytes remaining. - """ - stream = input_stream.InputStream('') - self.assertRaises(message.DecodeError, input_stream_method, stream) - - def testReadLittleEndian32(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadLittleEndian32) - s = '' - # Read 0. - s += '\x00\x00\x00\x00' - # Read 1. - s += '\x01\x00\x00\x00' - # Read a bunch of different bytes. - s += '\x01\x02\x03\x04' - # Read max unsigned 32-bit int. - s += '\xff\xff\xff\xff' - # Try a read with fewer than 4 bytes left in the stream. - s += '\x00\x00\x00' - stream = input_stream.InputStream(s) - self.assertEqual(0, stream.ReadLittleEndian32()) - self.assertEqual(4, stream.Position()) - self.assertEqual(1, stream.ReadLittleEndian32()) - self.assertEqual(8, stream.Position()) - self.assertEqual(0x04030201, stream.ReadLittleEndian32()) - self.assertEqual(12, stream.Position()) - self.assertEqual(wire_format.UINT32_MAX, stream.ReadLittleEndian32()) - self.assertEqual(16, stream.Position()) - self.assertRaises(message.DecodeError, stream.ReadLittleEndian32) - - def testReadLittleEndian64(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadLittleEndian64) - s = '' - # Read 0. - s += '\x00\x00\x00\x00\x00\x00\x00\x00' - # Read 1. - s += '\x01\x00\x00\x00\x00\x00\x00\x00' - # Read a bunch of different bytes. - s += '\x01\x02\x03\x04\x05\x06\x07\x08' - # Read max unsigned 64-bit int. - s += '\xff\xff\xff\xff\xff\xff\xff\xff' - # Try a read with fewer than 8 bytes left in the stream. - s += '\x00\x00\x00' - stream = input_stream.InputStream(s) - self.assertEqual(0, stream.ReadLittleEndian64()) - self.assertEqual(8, stream.Position()) - self.assertEqual(1, stream.ReadLittleEndian64()) - self.assertEqual(16, stream.Position()) - self.assertEqual(0x0807060504030201, stream.ReadLittleEndian64()) - self.assertEqual(24, stream.Position()) - self.assertEqual(wire_format.UINT64_MAX, stream.ReadLittleEndian64()) - self.assertEqual(32, stream.Position()) - self.assertRaises(message.DecodeError, stream.ReadLittleEndian64) - - def ReadVarintSuccessTestHelper(self, varints_and_ints, read_method): - """Helper for tests below that test successful reads of various varints. - - Args: - varints_and_ints: Iterable of (str, integer) pairs, where the string - gives the wire encoding and the integer gives the value we expect - to be returned by the read_method upon encountering this string. - read_method: Unbound InputStream method that is capable of reading - the encoded strings provided in the first elements of varints_and_ints. - """ - s = ''.join(s for s, i in varints_and_ints) - stream = input_stream.InputStream(s) - expected_pos = 0 - self.assertEqual(expected_pos, stream.Position()) - for s, expected_int in varints_and_ints: - self.assertEqual(expected_int, read_method(stream)) - expected_pos += len(s) - self.assertEqual(expected_pos, stream.Position()) - - def testReadVarint32Success(self): - varints_and_ints = [ - ('\x00', 0), - ('\x01', 1), - ('\x7f', 127), - ('\x80\x01', 128), - ('\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01', -1), - ('\xff\xff\xff\xff\x07', wire_format.INT32_MAX), - ('\x80\x80\x80\x80\xf8\xff\xff\xff\xff\x01', wire_format.INT32_MIN), - ] - self.ReadVarintSuccessTestHelper(varints_and_ints, - input_stream.InputStream.ReadVarint32) - - def testReadVarint32Failure(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarint32) - - # Try and fail to read INT32_MAX + 1. - s = '\x80\x80\x80\x80\x08' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarint32) - - # Try and fail to read INT32_MIN - 1. - s = '\xfe\xff\xff\xff\xf7\xff\xff\xff\xff\x01' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarint32) - - # Try and fail to read something that looks like - # a varint with more than 10 bytes. - s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarint32) - - def testReadVarUInt32Success(self): - varints_and_ints = [ - ('\x00', 0), - ('\x01', 1), - ('\x7f', 127), - ('\x80\x01', 128), - ('\xff\xff\xff\xff\x0f', wire_format.UINT32_MAX), - ] - self.ReadVarintSuccessTestHelper(varints_and_ints, - input_stream.InputStream.ReadVarUInt32) - - def testReadVarUInt32Failure(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarUInt32) - # Try and fail to read UINT32_MAX + 1 - s = '\x80\x80\x80\x80\x10' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarUInt32) - - # Try and fail to read something that looks like - # a varint with more than 10 bytes. - s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarUInt32) - - def testReadVarint64Success(self): - varints_and_ints = [ - ('\x00', 0), - ('\x01', 1), - ('\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01', -1), - ('\x7f', 127), - ('\x80\x01', 128), - ('\xff\xff\xff\xff\xff\xff\xff\xff\x7f', wire_format.INT64_MAX), - ('\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01', wire_format.INT64_MIN), - ] - self.ReadVarintSuccessTestHelper(varints_and_ints, - input_stream.InputStream.ReadVarint64) - - def testReadVarint64Failure(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarint64) - # Try and fail to read something with the mythical 64th bit set. - s = '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarint64) - - # Try and fail to read something that looks like - # a varint with more than 10 bytes. - s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarint64) - - def testReadVarUInt64Success(self): - varints_and_ints = [ - ('\x00', 0), - ('\x01', 1), - ('\x7f', 127), - ('\x80\x01', 128), - ('\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01', 1 << 63), - ] - self.ReadVarintSuccessTestHelper(varints_and_ints, - input_stream.InputStream.ReadVarUInt64) - - def testReadVarUInt64Failure(self): - self.EnsureFailureOnEmptyStream(input_stream.InputStream.ReadVarUInt64) - # Try and fail to read something with the mythical 64th bit set. - s = '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarUInt64) - - # Try and fail to read something that looks like - # a varint with more than 10 bytes. - s = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' - stream = input_stream.InputStream(s) - self.assertRaises(message.DecodeError, stream.ReadVarUInt64) - - -class InputStreamArrayTest(InputStreamBufferTest): - - def setUp(self): - # Test InputStreamArray against the same tests in InputStreamBuffer - self.__original_input_stream = input_stream.InputStream - input_stream.InputStream = input_stream.InputStreamArray - - def tearDown(self): - input_stream.InputStream = self.__original_input_stream - - -if __name__ == '__main__': - unittest.main() diff --git a/python/google/protobuf/internal/message_listener.py b/python/google/protobuf/internal/message_listener.py index 43978952..1080234d 100755 --- a/python/google/protobuf/internal/message_listener.py +++ b/python/google/protobuf/internal/message_listener.py @@ -39,22 +39,34 @@ __author__ = 'robinson@google.com (Will Robinson)' class MessageListener(object): - """Listens for transitions to nonempty and for invalidations of cached - byte sizes. Meant to be registered via Message._SetListener(). + """Listens for modifications made to a message. Meant to be registered via + Message._SetListener(). + + Attributes: + dirty: If True, then calling Modified() would be a no-op. This can be + used to avoid these calls entirely in the common case. """ - def TransitionToNonempty(self): - """Called the *first* time that this message becomes nonempty. - Implementations are free (but not required) to call this method multiple - times after the message has become nonempty. - """ - raise NotImplementedError + def Modified(self): + """Called every time the message is modified in such a way that the parent + message may need to be updated. This currently means either: + (a) The message was modified for the first time, so the parent message + should henceforth mark the message as present. + (b) The message's cached byte size became dirty -- i.e. the message was + modified for the first time after a previous call to ByteSize(). + Therefore the parent should also mark its byte size as dirty. + Note that (a) implies (b), since new objects start out with a client cached + size (zero). However, we document (a) explicitly because it is important. + + Modified() will *only* be called in response to one of these two events -- + not every time the sub-message is modified. - def ByteSizeDirty(self): - """Called *every* time the cached byte size value - for this object is invalidated (transitions from being - "clean" to "dirty"). + Note that if the listener's |dirty| attribute is true, then calling + Modified at the moment would be a no-op, so it can be skipped. Performance- + sensitive callers should check this attribute directly before calling since + it will be true most of the time. """ + raise NotImplementedError @@ -62,8 +74,5 @@ class NullMessageListener(object): """No-op MessageListener implementation.""" - def TransitionToNonempty(self): - pass - - def ByteSizeDirty(self): + def Modified(self): pass diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index df344cf0..73a9a3a3 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -30,7 +30,16 @@ # (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.""" +"""Tests python protocol buffers against the golden message. + +Note that the golden messages exercise every known field type, thus this +test ends up exercising and verifying nearly all of the parsing and +serialization code in the whole library. + +TODO(kenton): Merge with wire_format_test? It doesn't make a whole lot of +sense to call this a test of the "message" module, which only declares an +abstract interface. +""" __author__ = 'gps@google.com (Gregory P. Smith)' @@ -40,14 +49,41 @@ from google.protobuf import unittest_pb2 from google.protobuf.internal import test_util -class MessageTest(test_util.GoldenMessageTestCase): +class MessageTest(unittest.TestCase): 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) + test_util.ExpectAllFieldsSet(self, golden_message) + self.assertTrue(golden_message.SerializeToString() == golden_data) + + def testGoldenExtensions(self): + golden_data = test_util.GoldenFile('golden_message').read() + golden_message = unittest_pb2.TestAllExtensions() + golden_message.ParseFromString(golden_data) + all_set = unittest_pb2.TestAllExtensions() + test_util.SetAllExtensions(all_set) + self.assertEquals(all_set, golden_message) + self.assertTrue(golden_message.SerializeToString() == golden_data) + + def testGoldenPackedMessage(self): + golden_data = test_util.GoldenFile('golden_packed_fields_message').read() + golden_message = unittest_pb2.TestPackedTypes() + golden_message.ParseFromString(golden_data) + all_set = unittest_pb2.TestPackedTypes() + test_util.SetAllPackedFields(all_set) + self.assertEquals(all_set, golden_message) + self.assertTrue(all_set.SerializeToString() == golden_data) + def testGoldenPackedExtensions(self): + golden_data = test_util.GoldenFile('golden_packed_fields_message').read() + golden_message = unittest_pb2.TestPackedExtensions() + golden_message.ParseFromString(golden_data) + all_set = unittest_pb2.TestPackedExtensions() + test_util.SetAllPackedExtensions(all_set) + self.assertEquals(all_set, golden_message) + self.assertTrue(all_set.SerializeToString() == golden_data) if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/output_stream.py b/python/google/protobuf/internal/output_stream.py deleted file mode 100755 index 6c2d6f6b..00000000 --- a/python/google/protobuf/internal/output_stream.py +++ /dev/null @@ -1,125 +0,0 @@ -# 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. - -"""OutputStream is the primitive interface for sticking bits on the wire. - -All protocol buffer serialization can be expressed in terms of -the OutputStream primitives provided here. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import array -import struct -from google.protobuf import message -from google.protobuf.internal import wire_format - - - -# Note that much of this code is ported from //net/proto/ProtocolBuffer, and -# that the interface is strongly inspired by CodedOutputStream from the C++ -# proto2 implementation. - - -class OutputStream(object): - - """Contains all logic for writing bits, and ToString() to get the result.""" - - def __init__(self): - self._buffer = array.array('B') - - def AppendRawBytes(self, raw_bytes): - """Appends raw_bytes to our internal buffer.""" - self._buffer.fromstring(raw_bytes) - - def AppendLittleEndian32(self, unsigned_value): - """Appends an unsigned 32-bit integer to the internal buffer, - in little-endian byte order. - """ - if not 0 <= unsigned_value <= wire_format.UINT32_MAX: - raise message.EncodeError( - 'Unsigned 32-bit out of range: %d' % unsigned_value) - self._buffer.fromstring(struct.pack( - wire_format.FORMAT_UINT32_LITTLE_ENDIAN, unsigned_value)) - - def AppendLittleEndian64(self, unsigned_value): - """Appends an unsigned 64-bit integer to the internal buffer, - in little-endian byte order. - """ - if not 0 <= unsigned_value <= wire_format.UINT64_MAX: - raise message.EncodeError( - 'Unsigned 64-bit out of range: %d' % unsigned_value) - self._buffer.fromstring(struct.pack( - wire_format.FORMAT_UINT64_LITTLE_ENDIAN, unsigned_value)) - - def AppendVarint32(self, value): - """Appends a signed 32-bit integer to the internal buffer, - encoded as a varint. (Note that a negative varint32 will - always require 10 bytes of space.) - """ - if not wire_format.INT32_MIN <= value <= wire_format.INT32_MAX: - raise message.EncodeError('Value out of range: %d' % value) - self.AppendVarint64(value) - - def AppendVarUInt32(self, value): - """Appends an unsigned 32-bit integer to the internal buffer, - encoded as a varint. - """ - if not 0 <= value <= wire_format.UINT32_MAX: - raise message.EncodeError('Value out of range: %d' % value) - self.AppendVarUInt64(value) - - def AppendVarint64(self, value): - """Appends a signed 64-bit integer to the internal buffer, - encoded as a varint. - """ - if not wire_format.INT64_MIN <= value <= wire_format.INT64_MAX: - raise message.EncodeError('Value out of range: %d' % value) - if value < 0: - value += (1 << 64) - self.AppendVarUInt64(value) - - def AppendVarUInt64(self, unsigned_value): - """Appends an unsigned 64-bit integer to the internal buffer, - encoded as a varint. - """ - if not 0 <= unsigned_value <= wire_format.UINT64_MAX: - raise message.EncodeError('Value out of range: %d' % unsigned_value) - while True: - bits = unsigned_value & 0x7f - unsigned_value >>= 7 - if not unsigned_value: - self._buffer.append(bits) - break - self._buffer.append(0x80|bits) - - def ToString(self): - """Returns a string containing the bytes in our internal buffer.""" - return self._buffer.tostring() diff --git a/python/google/protobuf/internal/output_stream_test.py b/python/google/protobuf/internal/output_stream_test.py deleted file mode 100755 index df92eecd..00000000 --- a/python/google/protobuf/internal/output_stream_test.py +++ /dev/null @@ -1,178 +0,0 @@ -#! /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. - -"""Test for google.protobuf.internal.output_stream.""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import unittest -from google.protobuf import message -from google.protobuf.internal import output_stream -from google.protobuf.internal import wire_format - - -class OutputStreamTest(unittest.TestCase): - - def setUp(self): - self.stream = output_stream.OutputStream() - - def testAppendRawBytes(self): - # Empty string. - self.stream.AppendRawBytes('') - self.assertEqual('', self.stream.ToString()) - - # Nonempty string. - self.stream.AppendRawBytes('abc') - self.assertEqual('abc', self.stream.ToString()) - - # Ensure that we're actually appending. - self.stream.AppendRawBytes('def') - self.assertEqual('abcdef', self.stream.ToString()) - - def AppendNumericTestHelper(self, append_fn, values_and_strings): - """For each (value, expected_string) pair in values_and_strings, - calls an OutputStream.Append*(value) method on an OutputStream and ensures - that the string written to that stream matches expected_string. - - Args: - append_fn: Unbound OutputStream method that takes an integer or - long value as input. - values_and_strings: Iterable of (value, expected_string) pairs. - """ - for conversion in (int, long): - for value, string in values_and_strings: - stream = output_stream.OutputStream() - expected_string = '' - append_fn(stream, conversion(value)) - expected_string += string - self.assertEqual(expected_string, stream.ToString()) - - def AppendOverflowTestHelper(self, append_fn, value): - """Calls an OutputStream.Append*(value) method and asserts - that the method raises message.EncodeError. - - Args: - append_fn: Unbound OutputStream method that takes an integer or - long value as input. - value: Value to pass to append_fn which should cause an - message.EncodeError. - """ - stream = output_stream.OutputStream() - self.assertRaises(message.EncodeError, append_fn, stream, value) - - def testAppendLittleEndian32(self): - append_fn = output_stream.OutputStream.AppendLittleEndian32 - values_and_expected_strings = [ - (0, '\x00\x00\x00\x00'), - (1, '\x01\x00\x00\x00'), - ((1 << 32) - 1, '\xff\xff\xff\xff'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, 1 << 32) - self.AppendOverflowTestHelper(append_fn, -1) - - def testAppendLittleEndian64(self): - append_fn = output_stream.OutputStream.AppendLittleEndian64 - values_and_expected_strings = [ - (0, '\x00\x00\x00\x00\x00\x00\x00\x00'), - (1, '\x01\x00\x00\x00\x00\x00\x00\x00'), - ((1 << 64) - 1, '\xff\xff\xff\xff\xff\xff\xff\xff'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, 1 << 64) - self.AppendOverflowTestHelper(append_fn, -1) - - def testAppendVarint32(self): - append_fn = output_stream.OutputStream.AppendVarint32 - values_and_expected_strings = [ - (0, '\x00'), - (1, '\x01'), - (127, '\x7f'), - (128, '\x80\x01'), - (-1, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'), - (wire_format.INT32_MAX, '\xff\xff\xff\xff\x07'), - (wire_format.INT32_MIN, '\x80\x80\x80\x80\xf8\xff\xff\xff\xff\x01'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, wire_format.INT32_MAX + 1) - self.AppendOverflowTestHelper(append_fn, wire_format.INT32_MIN - 1) - - def testAppendVarUInt32(self): - append_fn = output_stream.OutputStream.AppendVarUInt32 - values_and_expected_strings = [ - (0, '\x00'), - (1, '\x01'), - (127, '\x7f'), - (128, '\x80\x01'), - (wire_format.UINT32_MAX, '\xff\xff\xff\xff\x0f'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, -1) - self.AppendOverflowTestHelper(append_fn, wire_format.UINT32_MAX + 1) - - def testAppendVarint64(self): - append_fn = output_stream.OutputStream.AppendVarint64 - values_and_expected_strings = [ - (0, '\x00'), - (1, '\x01'), - (127, '\x7f'), - (128, '\x80\x01'), - (-1, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'), - (wire_format.INT64_MAX, '\xff\xff\xff\xff\xff\xff\xff\xff\x7f'), - (wire_format.INT64_MIN, '\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, wire_format.INT64_MAX + 1) - self.AppendOverflowTestHelper(append_fn, wire_format.INT64_MIN - 1) - - def testAppendVarUInt64(self): - append_fn = output_stream.OutputStream.AppendVarUInt64 - values_and_expected_strings = [ - (0, '\x00'), - (1, '\x01'), - (127, '\x7f'), - (128, '\x80\x01'), - (wire_format.UINT64_MAX, '\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01'), - ] - self.AppendNumericTestHelper(append_fn, values_and_expected_strings) - - self.AppendOverflowTestHelper(append_fn, -1) - self.AppendOverflowTestHelper(append_fn, wire_format.UINT64_MAX + 1) - - -if __name__ == '__main__': - unittest.main() diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 86101774..2c9fa30b 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -38,6 +38,7 @@ pure-Python protocol compiler. __author__ = 'robinson@google.com (Will Robinson)' import operator +import struct import unittest # TODO(robinson): When we split this test in two, only some of these imports @@ -56,6 +57,51 @@ from google.protobuf.internal import test_util from google.protobuf.internal import decoder +class _MiniDecoder(object): + """Decodes a stream of values from a string. + + Once upon a time we actually had a class called decoder.Decoder. Then we + got rid of it during a redesign that made decoding much, much faster overall. + But a couple tests in this file used it to check that the serialized form of + a message was correct. So, this class implements just the methods that were + used by said tests, so that we don't have to rewrite the tests. + """ + + def __init__(self, bytes): + self._bytes = bytes + self._pos = 0 + + def ReadVarint(self): + result, self._pos = decoder._DecodeVarint(self._bytes, self._pos) + return result + + ReadInt32 = ReadVarint + ReadInt64 = ReadVarint + ReadUInt32 = ReadVarint + ReadUInt64 = ReadVarint + + def ReadSInt64(self): + return wire_format.ZigZagDecode(self.ReadVarint()) + + ReadSInt32 = ReadSInt64 + + def ReadFieldNumberAndWireType(self): + return wire_format.UnpackTag(self.ReadVarint()) + + def ReadFloat(self): + result = struct.unpack("> TAG_TYPE_BITS), (tag & _TAG_TYPE_MASK) + return (tag >> TAG_TYPE_BITS), (tag & TAG_TYPE_MASK) def ZigZagEncode(value): @@ -245,3 +246,23 @@ def _VarUInt64ByteSizeNoTag(uint64): if uint64 > UINT64_MAX: raise message.EncodeError('Value out of range: %d' % uint64) return 10 + + +NON_PACKABLE_TYPES = ( + descriptor.FieldDescriptor.TYPE_STRING, + descriptor.FieldDescriptor.TYPE_GROUP, + descriptor.FieldDescriptor.TYPE_MESSAGE, + descriptor.FieldDescriptor.TYPE_BYTES +) + + +def IsTypePackable(field_type): + """Return true iff packable = true is valid for fields of this type. + + Args: + field_type: a FieldDescriptor::Type value. + + Returns: + True iff fields of this type are packable. + """ + return field_type not in NON_PACKABLE_TYPES diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py index 9a88bdc8..f8398474 100755 --- a/python/google/protobuf/message.py +++ b/python/google/protobuf/message.py @@ -99,7 +99,7 @@ class Message(object): Args: other_msg: Message to copy into the current one. """ - if self == other_msg: + if self is other_msg: return self.Clear() self.MergeFrom(other_msg) @@ -108,6 +108,15 @@ class Message(object): """Clears all data that was set in the message.""" raise NotImplementedError + def SetInParent(self): + """Mark this as present in the parent. + + This normally happens automatically when you assign a field of a + sub-message, but sometimes you want to make the sub-message + present while keeping it empty. If you find yourself using this, + you may want to reconsider your design.""" + raise NotImplementedError + def IsInitialized(self): """Checks if the message is initialized. diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py index d65d8b67..5b238031 100755 --- a/python/google/protobuf/reflection.py +++ b/python/google/protobuf/reflection.py @@ -50,9 +50,13 @@ this file*. __author__ = 'robinson@google.com (Will Robinson)' -import heapq -import threading +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +import struct import weakref + # We use "as" to avoid name collisions with variables. from google.protobuf.internal import containers from google.protobuf.internal import decoder @@ -139,14 +143,26 @@ class GeneratedProtocolMessageType(type): type. """ descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] + + cls._decoders_by_tag = {} + cls._extensions_by_name = {} + cls._extensions_by_number = {} + if (descriptor.has_options and + descriptor.GetOptions().message_set_wire_format): + cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( + decoder.MessageSetItemDecoder(cls._extensions_by_number)) + # We act as a "friend" class of the descriptor, setting # its _concrete_class attribute the first time we use a # given descriptor to initialize a concrete protocol message - # class. + # class. We also attach stuff to each FieldDescriptor for quick + # lookup later on. concrete_class_attr_name = '_concrete_class' if not hasattr(descriptor, concrete_class_attr_name): setattr(descriptor, concrete_class_attr_name, cls) - cls._known_extensions = [] + for field in descriptor.fields: + _AttachFieldHelpers(cls, field) + _AddEnumValues(descriptor, cls) _AddInitMethod(descriptor, cls) _AddPropertiesForFields(descriptor, cls) @@ -184,30 +200,33 @@ def _PropertyName(proto_field_name): # return proto_field_name + "_" # return proto_field_name # """ + # Kenton says: The above is a BAD IDEA. People rely on being able to use + # getattr() and setattr() to reflectively manipulate field values. If we + # rename the properties, then every such user has to also make sure to apply + # the same transformation. Note that currently if you name a field "yield", + # you can still access it just fine using getattr/setattr -- it's not even + # that cumbersome to do so. + # TODO(kenton): Remove this method entirely if/when everyone agrees with my + # position. return proto_field_name -def _ValueFieldName(proto_field_name): - """Returns the name of the (internal) instance attribute which objects - should use to store the current value for a given protocol message field. - - Args: - proto_field_name: The protocol message field name, exactly - as it appears (or would appear) in a .proto file. - """ - return '_value_' + proto_field_name +def _VerifyExtensionHandle(message, extension_handle): + """Verify that the given extension handle is valid.""" + if not isinstance(extension_handle, _FieldDescriptor): + raise KeyError('HasExtension() expects an extension handle, got: %s' % + extension_handle) -def _HasFieldName(proto_field_name): - """Returns the name of the (internal) instance attribute which - objects should use to store a boolean telling whether this field - is explicitly set or not. + if not extension_handle.is_extension: + raise KeyError('"%s" is not an extension.' % extension_handle.full_name) - Args: - proto_field_name: The protocol message field name, exactly - as it appears (or would appear) in a .proto file. - """ - return '_has_' + proto_field_name + if extension_handle.containing_type is not message.DESCRIPTOR: + raise KeyError('Extension "%s" extends message type "%s", but this ' + 'message is of type "%s".' % + (extension_handle.full_name, + extension_handle.containing_type.full_name, + message.DESCRIPTOR.full_name)) def _AddSlots(message_descriptor, dictionary): @@ -218,16 +237,57 @@ def _AddSlots(message_descriptor, dictionary): message_descriptor: A Descriptor instance describing this message type. dictionary: Class dictionary to which we'll add a '__slots__' entry. """ - field_names = [_ValueFieldName(f.name) for f in message_descriptor.fields] - field_names.extend(_HasFieldName(f.name) for f in message_descriptor.fields - if f.label != _FieldDescriptor.LABEL_REPEATED) - field_names.extend(('Extensions', - '_cached_byte_size', - '_cached_byte_size_dirty', - '_called_transition_to_nonempty', - '_listener', - '_lock', '__weakref__')) - dictionary['__slots__'] = field_names + dictionary['__slots__'] = ['_cached_byte_size', + '_cached_byte_size_dirty', + '_fields', + '_is_present_in_parent', + '_listener', + '_listener_for_children', + '__weakref__'] + + +def _IsMessageSetExtension(field): + return (field.is_extension and + field.containing_type.has_options and + field.containing_type.GetOptions().message_set_wire_format and + field.type == _FieldDescriptor.TYPE_MESSAGE and + field.message_type == field.extension_scope and + field.label == _FieldDescriptor.LABEL_OPTIONAL) + + +def _AttachFieldHelpers(cls, field_descriptor): + is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED) + is_packed = (field_descriptor.has_options and + field_descriptor.GetOptions().packed) + + if _IsMessageSetExtension(field_descriptor): + field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number) + sizer = encoder.MessageSetItemSizer(field_descriptor.number) + else: + field_encoder = type_checkers.TYPE_TO_ENCODER[field_descriptor.type]( + field_descriptor.number, is_repeated, is_packed) + sizer = type_checkers.TYPE_TO_SIZER[field_descriptor.type]( + field_descriptor.number, is_repeated, is_packed) + + field_descriptor._encoder = field_encoder + field_descriptor._sizer = sizer + field_descriptor._default_constructor = _DefaultValueConstructorForField( + field_descriptor) + + def AddDecoder(wiretype, is_packed): + tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype) + cls._decoders_by_tag[tag_bytes] = ( + type_checkers.TYPE_TO_DECODER[field_descriptor.type]( + field_descriptor.number, is_repeated, is_packed, + field_descriptor, field_descriptor._default_constructor)) + + AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type], + False) + + if is_repeated and wire_format.IsTypePackable(field_descriptor.type): + # To support wire compatibility of adding packed = true, add a decoder for + # packed values regardless of the field's options. + AddDecoder(wire_format.WIRETYPE_LENGTH_DELIMITED, True) def _AddClassAttributesForNestedExtensions(descriptor, dictionary): @@ -249,44 +309,51 @@ def _AddEnumValues(descriptor, cls): setattr(cls, enum_value.name, enum_value.number) -def _DefaultValueForField(message, field): - """Returns a default value for a field. +def _DefaultValueConstructorForField(field): + """Returns a function which returns a default value for a field. Args: + field: FieldDescriptor object for this field. + + The returned function has one argument: message: Message instance containing this field, or a weakref proxy of same. - field: FieldDescriptor object for this field. - Returns: A default value for this field. May refer back to |message| - via a weak reference. + That function in turn returns a default value for this field. The default + value may refer back to |message| via a weak reference. """ - # TODO(robinson): Only the repeated fields need a reference to 'message' (so - # that they can set the 'has' bit on the containing Message when someone - # append()s a value). We could special-case this, and avoid an extra - # function call on __init__() and Clear() for non-repeated fields. - - # TODO(robinson): Find a better place for the default value assertion in this - # function. No need to repeat them every time the client calls Clear('foo'). - # (We should probably just assert these things once and as early as possible, - # by tightening checking in the descriptor classes.) + if field.label == _FieldDescriptor.LABEL_REPEATED: if field.default_value != []: raise ValueError('Repeated field default value not empty list: %s' % ( field.default_value)) - listener = _Listener(message, None) if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: # We can't look at _concrete_class yet since it might not have # been set. (Depends on order in which we initialize the classes). - return containers.RepeatedCompositeFieldContainer( - listener, field.message_type) + message_type = field.message_type + def MakeRepeatedMessageDefault(message): + return containers.RepeatedCompositeFieldContainer( + message._listener_for_children, field.message_type) + return MakeRepeatedMessageDefault else: - return containers.RepeatedScalarFieldContainer( - listener, type_checkers.GetTypeChecker(field.cpp_type, field.type)) + type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type) + def MakeRepeatedScalarDefault(message): + return containers.RepeatedScalarFieldContainer( + message._listener_for_children, type_checker) + return MakeRepeatedScalarDefault if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - assert field.default_value is None + # _concrete_class may not yet be initialized. + message_type = field.message_type + def MakeSubMessageDefault(message): + result = message_type._concrete_class() + result._SetListener(message._listener_for_children) + return result + return MakeSubMessageDefault - return field.default_value + def MakeScalarDefault(message): + return field.default_value + return MakeScalarDefault def _AddInitMethod(message_descriptor, cls): @@ -295,21 +362,29 @@ def _AddInitMethod(message_descriptor, cls): def init(self, **kwargs): self._cached_byte_size = 0 self._cached_byte_size_dirty = False + self._fields = {} + self._is_present_in_parent = False self._listener = message_listener_mod.NullMessageListener() - self._called_transition_to_nonempty = False - # TODO(robinson): We should only create a lock if we really need one - # in this class. - self._lock = threading.Lock() - for field in fields: - default_value = _DefaultValueForField(self, field) - python_field_name = _ValueFieldName(field.name) - setattr(self, python_field_name, default_value) - if field.label != _FieldDescriptor.LABEL_REPEATED: - setattr(self, _HasFieldName(field.name), False) - self.Extensions = _ExtensionDict(self, cls._known_extensions) + self._listener_for_children = _Listener(self) for field_name, field_value in kwargs.iteritems(): field = _GetFieldByName(message_descriptor, field_name) - _MergeFieldOrExtension(self, field, field_value) + if field is None: + raise TypeError("%s() got an unexpected keyword argument '%s'" % + (message_descriptor.name, field_name)) + if field.label == _FieldDescriptor.LABEL_REPEATED: + copy = field._default_constructor(self) + if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: # Composite + for val in field_value: + copy.add().MergeFrom(val) + else: # Scalar + copy.extend(field_value) + self._fields[field] = copy + elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + copy = field._default_constructor(self) + copy.MergeFrom(field_value) + self._fields[field] = copy + else: + self._fields[field] = field_value init.__module__ = None init.__doc__ = None @@ -336,6 +411,11 @@ def _AddPropertiesForFields(descriptor, cls): for field in descriptor.fields: _AddPropertiesForField(field, cls) + if descriptor.is_extendable: + # _ExtensionDict is just an adaptor with no state so we allocate a new one + # every time it is accessed. + cls.Extensions = property(lambda self: _ExtensionDict(self)) + def _AddPropertiesForField(field, cls): """Adds a public property for a protocol message field. @@ -377,11 +457,22 @@ def _AddPropertiesForRepeatedField(field, cls): cls: The class we're constructing. """ proto_field_name = field.name - python_field_name = _ValueFieldName(proto_field_name) property_name = _PropertyName(proto_field_name) def getter(self): - return getattr(self, python_field_name) + field_value = self._fields.get(field) + if field_value is None: + # Construct a new object to represent this field. + field_value = field._default_constructor(self) + + # Atomically check if another thread has preempted us and, if not, swap + # in the new object we just created. If someone has preempted us, we + # take that object and discard ours. + # WARNING: We are relying on setdefault() being atomic. This is true + # in CPython but we haven't investigated others. This warning appears + # in several other locations in this file. + field_value = self._fields.setdefault(field, field_value) + return field_value getter.__module__ = None getter.__doc__ = 'Getter for %s.' % proto_field_name @@ -407,21 +498,21 @@ def _AddPropertiesForNonRepeatedScalarField(field, cls): cls: The class we're constructing. """ proto_field_name = field.name - python_field_name = _ValueFieldName(proto_field_name) - has_field_name = _HasFieldName(proto_field_name) property_name = _PropertyName(proto_field_name) type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type) + default_value = field.default_value def getter(self): - return getattr(self, python_field_name) + return self._fields.get(field, default_value) getter.__module__ = None getter.__doc__ = 'Getter for %s.' % proto_field_name def setter(self, new_value): type_checker.CheckValue(new_value) - setattr(self, has_field_name, True) - self._MarkByteSizeDirty() - self._MaybeCallTransitionToNonemptyCallback() - setattr(self, python_field_name, new_value) + self._fields[field] = new_value + # Check _cached_byte_size_dirty inline to improve performance, since scalar + # setters are called frequently. + if not self._cached_byte_size_dirty: + self._Modified() setter.__module__ = None setter.__doc__ = 'Setter for %s.' % proto_field_name @@ -444,25 +535,23 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls): # TODO(robinson): Remove duplication with similar method # for non-repeated scalars. proto_field_name = field.name - python_field_name = _ValueFieldName(proto_field_name) - has_field_name = _HasFieldName(proto_field_name) property_name = _PropertyName(proto_field_name) message_type = field.message_type def getter(self): - # TODO(robinson): Appropriately scary note about double-checked locking. - field_value = getattr(self, python_field_name) + field_value = self._fields.get(field) if field_value is None: - self._lock.acquire() - try: - field_value = getattr(self, python_field_name) - if field_value is None: - field_class = message_type._concrete_class - field_value = field_class() - field_value._SetListener(_Listener(self, has_field_name)) - setattr(self, python_field_name, field_value) - finally: - self._lock.release() + # Construct a new object to represent this field. + field_value = message_type._concrete_class() + field_value._SetListener(self._listener_for_children) + + # Atomically check if another thread has preempted us and, if not, swap + # in the new object we just created. If someone has preempted us, we + # take that object and discard ours. + # WARNING: We are relying on setdefault() being atomic. This is true + # in CPython but we haven't investigated others. This warning appears + # in several other locations in this file. + field_value = self._fields.setdefault(field, field_value) return field_value getter.__module__ = None getter.__doc__ = 'Getter for %s.' % proto_field_name @@ -490,7 +579,27 @@ def _AddStaticMethods(cls): # TODO(robinson): This probably needs to be thread-safe(?) def RegisterExtension(extension_handle): extension_handle.containing_type = cls.DESCRIPTOR - cls._known_extensions.append(extension_handle) + _AttachFieldHelpers(cls, extension_handle) + + # Try to insert our extension, failing if an extension with the same number + # already exists. + actual_handle = cls._extensions_by_number.setdefault( + extension_handle.number, extension_handle) + if actual_handle is not extension_handle: + raise AssertionError( + 'Extensions "%s" and "%s" both try to extend message type "%s" with ' + 'field number %d.' % + (extension_handle.full_name, actual_handle.full_name, + cls.DESCRIPTOR.full_name, extension_handle.number)) + + cls._extensions_by_name[extension_handle.full_name] = extension_handle + + handle = extension_handle # avoid line wrapping + if _IsMessageSetExtension(handle): + # MessageSet extension. Also register under type name. + cls._extensions_by_name[ + extension_handle.message_type.full_name] = extension_handle + cls.RegisterExtension = staticmethod(RegisterExtension) def FromString(s): @@ -500,115 +609,107 @@ def _AddStaticMethods(cls): cls.FromString = staticmethod(FromString) +def _IsPresent(item): + """Given a (FieldDescriptor, value) tuple from _fields, return true if the + value should be included in the list returned by ListFields().""" + + if item[0].label == _FieldDescriptor.LABEL_REPEATED: + return bool(item[1]) + elif item[0].cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + return item[1]._is_present_in_parent + else: + return True + + def _AddListFieldsMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" - # Ensure that we always list in ascending field-number order. - # For non-extension fields, we can do the sort once, here, at import-time. - # For extensions, we sort on each ListFields() call, though - # we could do better if we have to. - fields = sorted(message_descriptor.fields, key=lambda f: f.number) - has_field_names = (_HasFieldName(f.name) for f in fields) - value_field_names = (_ValueFieldName(f.name) for f in fields) - triplets = zip(has_field_names, value_field_names, fields) - def ListFields(self): - # We need to list all extension and non-extension fields - # together, in sorted order by field number. - - # Step 0: Get an iterator over all "set" non-extension fields, - # sorted by field number. - # This iterator yields (field_number, field_descriptor, value) tuples. - def SortedSetFieldsIter(): - # Note that triplets is already sorted by field number. - for has_field_name, value_field_name, field_descriptor in triplets: - if field_descriptor.label == _FieldDescriptor.LABEL_REPEATED: - value = getattr(self, _ValueFieldName(field_descriptor.name)) - if len(value) > 0: - yield (field_descriptor.number, field_descriptor, value) - elif getattr(self, _HasFieldName(field_descriptor.name)): - value = getattr(self, _ValueFieldName(field_descriptor.name)) - yield (field_descriptor.number, field_descriptor, value) - sorted_fields = SortedSetFieldsIter() - - # Step 1: Get an iterator over all "set" extension fields, - # sorted by field number. - # This iterator ALSO yields (field_number, field_descriptor, value) tuples. - # TODO(robinson): It's not necessary to repeat this with each - # serialization call. We can do better. - sorted_extension_fields = sorted( - [(f.number, f, v) for f, v in self.Extensions._ListSetExtensions()]) - - # Step 2: Create a composite iterator that merges the extension- - # and non-extension fields, and that still yields fields in - # sorted order. - all_set_fields = _ImergeSorted(sorted_fields, sorted_extension_fields) - - # Step 3: Strip off the field numbers and return. - return [field[1:] for field in all_set_fields] + all_fields = [item for item in self._fields.iteritems() if _IsPresent(item)] + all_fields.sort(key = lambda item: item[0].number) + return all_fields cls.ListFields = ListFields -def _AddHasFieldMethod(cls): + +def _AddHasFieldMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" + + singular_fields = {} + for field in message_descriptor.fields: + if field.label != _FieldDescriptor.LABEL_REPEATED: + singular_fields[field.name] = field + def HasField(self, field_name): try: - return getattr(self, _HasFieldName(field_name)) - except AttributeError: - raise ValueError('Protocol message has no "%s" field.' % field_name) + field = singular_fields[field_name] + except KeyError: + raise ValueError( + 'Protocol message has no singular "%s" field.' % field_name) + + if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + value = self._fields.get(field) + return value is not None and value._is_present_in_parent + else: + return field in self._fields cls.HasField = HasField -def _AddClearFieldMethod(cls): +def _AddClearFieldMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" def ClearField(self, 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) - default_value = _DefaultValueForField(self, field) - if field.label == _FieldDescriptor.LABEL_REPEATED: - self._MarkByteSizeDirty() - else: - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - old_field_value = getattr(self, python_field_name) - if old_field_value is not None: - # Snip the old object out of the object tree. - old_field_value._SetListener(None) - if getattr(self, has_field_name): - setattr(self, has_field_name, False) - # Set dirty bit on ourself and parents only if - # we're actually changing state. - self._MarkByteSizeDirty() - setattr(self, python_field_name, default_value) + try: + field = message_descriptor.fields_by_name[field_name] + except KeyError: + raise ValueError('Protocol message has no "%s" field.' % field_name) + + if field in self._fields: + # Note: If the field is a sub-message, its listener will still point + # at us. That's fine, because the worst than can happen is that it + # will call _Modified() and invalidate our byte size. Big deal. + del self._fields[field] + + # Always call _Modified() -- even if nothing was changed, this is + # a mutating method, and thus calling it should cause the field to become + # present in the parent message. + self._Modified() + cls.ClearField = ClearField def _AddClearExtensionMethod(cls): """Helper for _AddMessageMethods().""" def ClearExtension(self, extension_handle): - self.Extensions._ClearExtension(extension_handle) + _VerifyExtensionHandle(self, extension_handle) + + # Similar to ClearField(), above. + if extension_handle in self._fields: + del self._fields[extension_handle] + self._Modified() cls.ClearExtension = ClearExtension -def _AddClearMethod(cls): +def _AddClearMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" def Clear(self): # Clear fields. - fields = self.DESCRIPTOR.fields - for field in fields: - self.ClearField(field.name) - # Clear extensions. - extensions = self.Extensions._ListSetExtensions() - for extension in extensions: - self.ClearExtension(extension[0]) + self._fields = {} + self._Modified() cls.Clear = Clear def _AddHasExtensionMethod(cls): """Helper for _AddMessageMethods().""" def HasExtension(self, extension_handle): - return self.Extensions._HasExtension(extension_handle) + _VerifyExtensionHandle(self, extension_handle) + if extension_handle.label == _FieldDescriptor.LABEL_REPEATED: + raise KeyError('"%s" is repeated.' % extension_handle.full_name) + + if extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + value = self._fields.get(extension_handle) + return value is not None and value._is_present_in_parent + else: + return extension_handle in self._fields cls.HasExtension = HasExtension @@ -622,26 +723,8 @@ def _AddEqualsMethod(message_descriptor, cls): if self is other: return True - # Compare all fields contained directly in this message. - for field_descriptor in message_descriptor.fields: - label = field_descriptor.label - property_name = _PropertyName(field_descriptor.name) - # Non-repeated field equality requires matching "has" bits as well - # as having an equal value. - if label != _FieldDescriptor.LABEL_REPEATED: - self_has = self.HasField(property_name) - other_has = other.HasField(property_name) - if self_has != other_has: - return False - if not self_has: - # If the "has" bit for this field is False, we must stop here. - # Otherwise we will recurse forever on recursively-defined protos. - continue - if getattr(self, property_name) != getattr(other, property_name): - return False + return self.ListFields() == other.ListFields() - # Compare the extensions present in both messages. - return self.Extensions == other.Extensions cls.__eq__ = __eq__ @@ -685,618 +768,202 @@ def _BytesForNonRepeatedElement(value, field_number, field_type): def _AddByteSizeMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" - def BytesForField(message, field, value): - """Returns the number of bytes required to serialize a single field - in message. The field may be repeated or not, composite or not. - - Args: - message: The Message instance containing a field of the given type. - field: A FieldDescriptor describing the field of interest. - value: The value whose byte size we're interested in. - - Returns: The number of bytes required to serialize the current value - of "field" in "message", including space for tags and any other - necessary information. - """ - - if _MessageSetField(field): - return wire_format.MessageSetItemByteSize(field.number, value) - - field_number, field_type = field.number, field.type - - # Repeated fields. - if field.label == _FieldDescriptor.LABEL_REPEATED: - elements = value - else: - elements = [value] - - if field.GetOptions().packed: - content_size = _ContentBytesForPackedField(message, field, elements) - if content_size: - tag_size = wire_format.TagByteSize(field_number) - length_size = wire_format.Int32ByteSizeNoTag(content_size) - return tag_size + length_size + content_size - else: - return 0 - else: - return sum(_BytesForNonRepeatedElement(element, field_number, field_type) - for element in elements) - - def _ContentBytesForPackedField(self, field, value): - """Returns the number of bytes required to serialize the actual - content of a packed field (not including the tag or the encoding - of the length. - - Args: - self: The Message instance containing a field of the given type. - field: A FieldDescriptor describing the field of interest. - value: The value whose byte size we're interested in. - - Returns: The number of bytes required to serialize the current value - of the packed "field" in "message", excluding space for tags and the - length encoding. - """ - size = sum(_BytesForNonRepeatedElement(element, field.number, field.type) - for element in value) - # In the packed case, there are no per element tags. - return size - wire_format.TagByteSize(field.number) * len(value) - - fields = message_descriptor.fields - has_field_names = (_HasFieldName(f.name) for f in fields) - zipped = zip(has_field_names, fields) - def ByteSize(self): if not self._cached_byte_size_dirty: return self._cached_byte_size size = 0 - # Hardcoded fields first. - for has_field_name, field in zipped: - if (field.label == _FieldDescriptor.LABEL_REPEATED - or getattr(self, has_field_name)): - value = getattr(self, _ValueFieldName(field.name)) - size += BytesForField(self, field, value) - # Extensions next. - for field, value in self.Extensions._ListSetExtensions(): - size += BytesForField(self, field, value) + for field_descriptor, field_value in self.ListFields(): + size += field_descriptor._sizer(field_value) self._cached_byte_size = size self._cached_byte_size_dirty = False + self._listener_for_children.dirty = False return size - cls._ContentBytesForPackedField = _ContentBytesForPackedField cls.ByteSize = ByteSize -def _MessageSetField(field_descriptor): - """Checks if a field should be serialized using the message set wire format. - - Args: - field_descriptor: Descriptor of the field. - - Returns: - True if the field should be serialized using the message set wire format, - false otherwise. - """ - return (field_descriptor.is_extension and - field_descriptor.label != _FieldDescriptor.LABEL_REPEATED and - field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and - field_descriptor.containing_type.GetOptions().message_set_wire_format) - - -def _SerializeValueToEncoder(value, field_number, field_descriptor, encoder): - """Appends the serialization of a single value to encoder. - - Args: - value: Value to serialize. - field_number: Field number of this value. - field_descriptor: Descriptor of the field to serialize. - encoder: encoder.Encoder object to which we should serialize this value. - """ - if _MessageSetField(field_descriptor): - encoder.AppendMessageSetItem(field_number, value) - return - - try: - method = type_checkers.TYPE_TO_SERIALIZE_METHOD[field_descriptor.type] - method(encoder, field_number, value) - except KeyError: - raise message_mod.EncodeError('Unrecognized field type: %d' % - field_descriptor.type) - - -def _ImergeSorted(*streams): - """Merges N sorted iterators into a single sorted iterator. - Each element in streams must be an iterable that yields - its elements in sorted order, and the elements contained - in each stream must all be comparable. - - There may be repeated elements in the component streams or - across the streams; the repeated elements will all be repeated - in the merged iterator as well. - - I believe that the heapq module at HEAD in the Python - sources has a method like this, but for now we roll our own. - """ - iters = [iter(stream) for stream in streams] - heap = [] - for index, it in enumerate(iters): - try: - heap.append((it.next(), index)) - except StopIteration: - pass - heapq.heapify(heap) - - while heap: - smallest_value, idx = heap[0] - yield smallest_value - try: - next_element = iters[idx].next() - heapq.heapreplace(heap, (next_element, idx)) - except StopIteration: - heapq.heappop(heap) - - def _AddSerializeToStringMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" def SerializeToString(self): # Check if the message has all of its required fields set. errors = [] - if not _InternalIsInitialized(self, errors): - raise message_mod.EncodeError('\n'.join(errors)) + if not self.IsInitialized(): + raise message_mod.EncodeError( + 'Message is missing required fields: ' + + ','.join(self.FindInitializationErrors())) return self.SerializePartialToString() cls.SerializeToString = SerializeToString def _AddSerializePartialToStringMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" - Encoder = encoder.Encoder def SerializePartialToString(self): - encoder = Encoder() - # We need to serialize all extension and non-extension fields - # together, in sorted order by field number. - for field_descriptor, field_value in self.ListFields(): - if field_descriptor.label == _FieldDescriptor.LABEL_REPEATED: - repeated_value = field_value - else: - repeated_value = [field_value] - if field_descriptor.GetOptions().packed: - # First, write the field number and WIRETYPE_LENGTH_DELIMITED. - field_number = field_descriptor.number - encoder.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - # Next, write the number of bytes. - content_bytes = self._ContentBytesForPackedField( - field_descriptor, field_value) - encoder.AppendInt32NoTag(content_bytes) - # Finally, write the actual values. - try: - method = type_checkers.TYPE_TO_NOTAG_SERIALIZE_METHOD[ - field_descriptor.type] - for value in repeated_value: - method(encoder, value) - except KeyError: - raise message_mod.EncodeError('Unrecognized field type: %d' % - field_descriptor.type) - else: - for element in repeated_value: - _SerializeValueToEncoder(element, field_descriptor.number, - field_descriptor, encoder) - return encoder.ToString() - + out = StringIO() + self._InternalSerialize(out.write) + return out.getvalue() cls.SerializePartialToString = SerializePartialToString + def InternalSerialize(self, write_bytes): + for field_descriptor, field_value in self.ListFields(): + field_descriptor._encoder(write_bytes, field_value) + cls._InternalSerialize = InternalSerialize -def _WireTypeForFieldType(field_type): - """Given a field type, returns the expected wire type.""" - try: - return type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_type] - except KeyError: - raise message_mod.DecodeError('Unknown field type: %d' % field_type) - - -def _WireTypeForField(field_descriptor): - """Given a field descriptor, returns the expected wire type.""" - if field_descriptor.GetOptions().packed: - return wire_format.WIRETYPE_LENGTH_DELIMITED - else: - return _WireTypeForFieldType(field_descriptor.type) - - -def _RecursivelyMerge(field_number, field_type, decoder, message): - """Decodes a message from decoder into message. - message is either a group or a nested message within some containing - protocol message. If it's a group, we use the group protocol to - deserialize, and if it's a nested message, we use the nested-message - protocol. - - Args: - field_number: The field number of message in its enclosing protocol buffer. - field_type: The field type of message. Must be either TYPE_MESSAGE - or TYPE_GROUP. - decoder: Decoder to read from. - message: Message to deserialize into. - """ - if field_type == _FieldDescriptor.TYPE_MESSAGE: - decoder.ReadMessageInto(message) - elif field_type == _FieldDescriptor.TYPE_GROUP: - decoder.ReadGroupInto(field_number, message) - else: - raise message_mod.DecodeError('Unexpected field type: %d' % field_type) - - -def _DeserializeScalarFromDecoder(field_type, decoder): - """Deserializes a scalar of the requested type from decoder. field_type must - be a scalar (non-group, non-message) FieldDescriptor.FIELD_* constant. - """ - try: - method = type_checkers.TYPE_TO_DESERIALIZE_METHOD[field_type] - return method(decoder) - except KeyError: - raise message_mod.DecodeError('Unrecognized field type: %d' % field_type) - - -def _SkipField(field_number, wire_type, decoder): - """Skips a field with the specified wire type. - - Args: - field_number: Tag number of the field to skip. - wire_type: Wire type of the field to skip. - decoder: Decoder used to deserialize the messsage. It must be positioned - just after reading the the tag and wire type of the field. - """ - if wire_type == wire_format.WIRETYPE_VARINT: - decoder.ReadUInt64() - elif wire_type == wire_format.WIRETYPE_FIXED64: - decoder.ReadFixed64() - elif wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED: - decoder.SkipBytes(decoder.ReadInt32()) - elif wire_type == wire_format.WIRETYPE_START_GROUP: - _SkipGroup(field_number, decoder) - elif wire_type == wire_format.WIRETYPE_END_GROUP: - pass - elif wire_type == wire_format.WIRETYPE_FIXED32: - decoder.ReadFixed32() - else: - raise message_mod.DecodeError('Unexpected wire type: %d' % wire_type) - - -def _SkipGroup(group_number, decoder): - """Skips a nested group from the decoder. - - Args: - group_number: Tag number of the group to skip. - decoder: Decoder used to deserialize the message. It must be positioned - exactly at the beginning of the message that should be skipped. - """ - while True: - field_number, wire_type = decoder.ReadFieldNumberAndWireType() - if (wire_type == wire_format.WIRETYPE_END_GROUP and - field_number == group_number): - return - _SkipField(field_number, wire_type, decoder) - - -def _DeserializeMessageSetItem(message, decoder): - """Deserializes a message using the message set wire format. - - Args: - message: Message to be parsed to. - decoder: The decoder to be used to deserialize encoded data. Note that the - decoder should be positioned just after reading the START_GROUP tag that - began the messageset item. - """ - field_number, wire_type = decoder.ReadFieldNumberAndWireType() - if wire_type != wire_format.WIRETYPE_VARINT or field_number != 2: - raise message_mod.DecodeError( - 'Incorrect message set wire format. ' - 'wire_type: %d, field_number: %d' % (wire_type, field_number)) - - type_id = decoder.ReadInt32() - field_number, wire_type = decoder.ReadFieldNumberAndWireType() - if wire_type != wire_format.WIRETYPE_LENGTH_DELIMITED or field_number != 3: - raise message_mod.DecodeError( - 'Incorrect message set wire format. ' - 'wire_type: %d, field_number: %d' % (wire_type, field_number)) - - extension_dict = message.Extensions - extensions_by_number = extension_dict._AllExtensionsByNumber() - if type_id not in extensions_by_number: - _SkipField(field_number, wire_type, decoder) - return - - field_descriptor = extensions_by_number[type_id] - value = extension_dict[field_descriptor] - decoder.ReadMessageInto(value) - # Read the END_GROUP tag. - field_number, wire_type = decoder.ReadFieldNumberAndWireType() - if wire_type != wire_format.WIRETYPE_END_GROUP or field_number != 1: - raise message_mod.DecodeError( - 'Incorrect message set wire format. ' - 'wire_type: %d, field_number: %d' % (wire_type, field_number)) - - -def _DeserializeOneEntity(message_descriptor, message, decoder): - """Deserializes the next wire entity from decoder into message. - - The next wire entity is either a scalar or a nested message, an - element in a repeated field (the wire encoding in this case is the - same), or a packed repeated field (in this case, the entire repeated - field is read by a single call to _DeserializeOneEntity). - - Args: - message_descriptor: A Descriptor instance describing all fields - in message. - message: The Message instance into which we're decoding our fields. - decoder: The Decoder we're using to deserialize encoded data. - - Returns: The number of bytes read from decoder during this method. - """ - initial_position = decoder.Position() - field_number, wire_type = decoder.ReadFieldNumberAndWireType() - extension_dict = message.Extensions - extensions_by_number = extension_dict._AllExtensionsByNumber() - if field_number in message_descriptor.fields_by_number: - # Non-extension field. - field_descriptor = message_descriptor.fields_by_number[field_number] - value = getattr(message, _PropertyName(field_descriptor.name)) - def nonextension_setter_fn(scalar): - setattr(message, _PropertyName(field_descriptor.name), scalar) - scalar_setter_fn = nonextension_setter_fn - elif field_number in extensions_by_number: - # Extension field. - field_descriptor = extensions_by_number[field_number] - value = extension_dict[field_descriptor] - def extension_setter_fn(scalar): - extension_dict[field_descriptor] = scalar - scalar_setter_fn = extension_setter_fn - elif wire_type == wire_format.WIRETYPE_END_GROUP: - # We assume we're being parsed as the group that's ended. - return 0 - elif (wire_type == wire_format.WIRETYPE_START_GROUP and - field_number == 1 and - message_descriptor.GetOptions().message_set_wire_format): - # A Message Set item. - _DeserializeMessageSetItem(message, decoder) - return decoder.Position() - initial_position - else: - _SkipField(field_number, wire_type, decoder) - return decoder.Position() - initial_position - - # If we reach this point, we've identified the field as either - # hardcoded or extension, and set |field_descriptor|, |scalar_setter_fn|, - # and |value| appropriately. Now actually deserialize the thing. - # - # field_descriptor: Describes the field we're deserializing. - # value: The value currently stored in the field to deserialize. - # Used only if the field is composite and/or repeated. - # scalar_setter_fn: A function F such that F(scalar) will - # set a nonrepeated scalar value for this field. Used only - # if this field is a nonrepeated scalar. - - field_number = field_descriptor.number - expected_wire_type = _WireTypeForField(field_descriptor) - if wire_type != expected_wire_type: - # Need to fill in uninterpreted_bytes. Work for the next CL. - raise RuntimeError('TODO(robinson): Wiretype mismatches not handled.') - - property_name = _PropertyName(field_descriptor.name) - label = field_descriptor.label - field_type = field_descriptor.type - cpp_type = field_descriptor.cpp_type - - # Nonrepeated scalar. Just set the field directly. - if (label != _FieldDescriptor.LABEL_REPEATED - and cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE): - scalar_setter_fn(_DeserializeScalarFromDecoder(field_type, decoder)) - return decoder.Position() - initial_position - - # Nonrepeated composite. Recursively deserialize. - if label != _FieldDescriptor.LABEL_REPEATED: - composite = value - _RecursivelyMerge(field_number, field_type, decoder, composite) - return decoder.Position() - initial_position - - # Now we know we're dealing with a repeated field of some kind. - element_list = value - - if cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE: - # Repeated scalar. - if not field_descriptor.GetOptions().packed: - element_list.append(_DeserializeScalarFromDecoder(field_type, decoder)) - return decoder.Position() - initial_position - else: - # Packed repeated field. - length = _DeserializeScalarFromDecoder( - _FieldDescriptor.TYPE_INT32, decoder) - content_start = decoder.Position() - while decoder.Position() - content_start < length: - element_list.append(_DeserializeScalarFromDecoder(field_type, decoder)) - return decoder.Position() - initial_position - else: - # Repeated composite. - composite = element_list.add() - _RecursivelyMerge(field_number, field_type, decoder, composite) - return decoder.Position() - initial_position - - -def _FieldOrExtensionValues(message, field_or_extension): - """Retrieves the list of values for the specified field or extension. - - The target field or extension can be optional, required or repeated, but it - must have value(s) set. The assumption is that the target field or extension - is set (e.g. _HasFieldOrExtension holds true). - Args: - message: Message which contains the target field or extension. - field_or_extension: Field or extension for which the list of values is - required. Must be an instance of FieldDescriptor. +def _AddMergeFromStringMethod(message_descriptor, cls): + """Helper for _AddMessageMethods().""" + def MergeFromString(self, serialized): + length = len(serialized) + try: + if self._InternalParse(serialized, 0, length) != length: + # The only reason _InternalParse would return early is if it + # encountered an end-group tag. + raise message_mod.DecodeError('Unexpected end-group tag.') + except IndexError: + raise message_mod.DecodeError('Truncated message.') + except struct.error, e: + raise message_mod.DecodeError(e) + return length # Return this for legacy reasons. + cls.MergeFromString = MergeFromString - Returns: - A list of values for the specified field or extension. This list will only - contain a single element if the field is non-repeated. - """ - if field_or_extension.is_extension: - value = message.Extensions[field_or_extension] - else: - value = getattr(message, _ValueFieldName(field_or_extension.name)) - if field_or_extension.label != _FieldDescriptor.LABEL_REPEATED: - return [value] - else: - # In this case value is a list or repeated values. - return value + local_ReadTag = decoder.ReadTag + local_SkipField = decoder.SkipField + decoders_by_tag = cls._decoders_by_tag + + def InternalParse(self, buffer, pos, end): + self._Modified() + field_dict = self._fields + while pos != end: + (tag_bytes, new_pos) = local_ReadTag(buffer, pos) + field_decoder = decoders_by_tag.get(tag_bytes) + if field_decoder is None: + new_pos = local_SkipField(buffer, new_pos, end, tag_bytes) + if new_pos == -1: + return pos + pos = new_pos + else: + pos = field_decoder(buffer, new_pos, end, self, field_dict) + return pos + cls._InternalParse = InternalParse -def _HasFieldOrExtension(message, field_or_extension): - """Checks if a message has the specified field or extension set. +def _AddIsInitializedMethod(message_descriptor, cls): + """Adds the IsInitialized and FindInitializationError methods to the + protocol message class.""" - The field or extension specified can be optional, required or repeated. If - it is repeated, this function returns True. Otherwise it checks the has bit - of the field or extension. + required_fields = [field for field in message_descriptor.fields + if field.label == _FieldDescriptor.LABEL_REQUIRED] - Args: - message: Message which contains the target field or extension. - field_or_extension: Field or extension to check. This must be a - FieldDescriptor instance. + def IsInitialized(self, errors=None): + """Checks if all required fields of a message are set. - Returns: - True if the message has a value set for the specified field or extension, - or if the field or extension is repeated. - """ - if field_or_extension.label == _FieldDescriptor.LABEL_REPEATED: - return True - if field_or_extension.is_extension: - return message.HasExtension(field_or_extension) - else: - return message.HasField(field_or_extension.name) + Args: + errors: A list which, if provided, will be populated with the field + paths of all missing required fields. + Returns: + True iff the specified message has all required fields set. + """ -def _IsFieldOrExtensionInitialized(message, field, errors=None): - """Checks if a message field or extension is initialized. + # Performance is critical so we avoid HasField() and ListFields(). - Args: - message: The message which contains the field or extension. - field: Field or extension to check. This must be a FieldDescriptor instance. - errors: Errors will be appended to it, if set to a meaningful value. + for field in required_fields: + if (field not in self._fields or + (field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and + not self._fields[field]._is_present_in_parent)): + if errors is not None: + errors.extend(self.FindInitializationErrors()) + return False - Returns: - True if the field/extension can be considered initialized. - """ - # If the field is required and is not set, it isn't initialized. - if field.label == _FieldDescriptor.LABEL_REQUIRED: - if not _HasFieldOrExtension(message, field): - if errors is not None: - errors.append('Required field %s is not set.' % field.full_name) - return False + for field, value in self._fields.iteritems(): + if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + if field.label == _FieldDescriptor.LABEL_REPEATED: + for element in value: + if not element.IsInitialized(): + if errors is not None: + errors.extend(self.FindInitializationErrors()) + return False + elif value._is_present_in_parent and not value.IsInitialized(): + if errors is not None: + errors.extend(self.FindInitializationErrors()) + return False - # If the field is optional and is not set, or if it - # isn't a submessage then the field is initialized. - if field.label == _FieldDescriptor.LABEL_OPTIONAL: - if not _HasFieldOrExtension(message, field): - return True - if field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE: return True - # The field is set and is either a single or a repeated submessage. - messages = _FieldOrExtensionValues(message, field) - # If all submessages in this field are initialized, the field is - # considered initialized. - for message in messages: - if not _InternalIsInitialized(message, errors): - return False - return True - + cls.IsInitialized = IsInitialized -def _InternalIsInitialized(message, errors=None): - """Checks if all required fields of a message are set. - - Args: - message: The message to check. - errors: If set, initialization errors will be appended to it. + def FindInitializationErrors(self): + """Finds required fields which are not initialized. - Returns: - True iff the specified message has all required fields set. - """ - fields_and_extensions = [] - fields_and_extensions.extend(message.DESCRIPTOR.fields) - fields_and_extensions.extend( - [extension[0] for extension in message.Extensions._ListSetExtensions()]) - for field_or_extension in fields_and_extensions: - if not _IsFieldOrExtensionInitialized(message, field_or_extension, errors): - return False - return True - - -def _AddMergeFromStringMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - Decoder = decoder.Decoder - def MergeFromString(self, serialized): - decoder = Decoder(serialized) - byte_count = 0 - while not decoder.EndOfStream(): - bytes_read = _DeserializeOneEntity(message_descriptor, self, decoder) - if not bytes_read: - break - byte_count += bytes_read - return byte_count - cls.MergeFromString = MergeFromString - - -def _AddIsInitializedMethod(cls): - """Adds the IsInitialized method to the protocol message class.""" - cls.IsInitialized = _InternalIsInitialized + Returns: + A list of strings. Each string is a path to an uninitialized field from + the top-level message, e.g. "foo.bar[5].baz". + """ + errors = [] # simplify things -def _MergeFieldOrExtension(destination_msg, field, value): - """Merges a specified message field into another message.""" - property_name = _PropertyName(field.name) - is_extension = field.is_extension + for field in required_fields: + if not self.HasField(field.name): + errors.append(field.name) - if not is_extension: - destination = getattr(destination_msg, property_name) - elif (field.label == _FieldDescriptor.LABEL_REPEATED or - field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE): - destination = destination_msg.Extensions[field] + for field, value in self.ListFields(): + if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + if field.is_extension: + name = "(%s)" % field.full_name + else: + name = field.name - # Case 1 - a composite field. - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - if field.label == _FieldDescriptor.LABEL_REPEATED: - for v in value: - destination.add().MergeFrom(v) - else: - destination.MergeFrom(value) - return + if field.label == _FieldDescriptor.LABEL_REPEATED: + for i in xrange(len(value)): + element = value[i] + prefix = "%s[%d]." % (name, i) + sub_errors = element.FindInitializationErrors() + errors += [ prefix + error for error in sub_errors ] + else: + prefix = name + "." + sub_errors = value.FindInitializationErrors() + errors += [ prefix + error for error in sub_errors ] - # Case 2 - a repeated field. - if field.label == _FieldDescriptor.LABEL_REPEATED: - for v in value: - destination.append(v) - return + return errors - # Case 3 - a singular field. - if is_extension: - destination_msg.Extensions[field] = value - else: - setattr(destination_msg, property_name, value) + cls.FindInitializationErrors = FindInitializationErrors def _AddMergeFromMethod(cls): + LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED + CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE + def MergeFrom(self, msg): assert msg is not self - for field in msg.ListFields(): - _MergeFieldOrExtension(self, field[0], field[1]) + self._Modified() + + fields = self._fields + + for field, value in msg._fields.iteritems(): + if field.label == LABEL_REPEATED or field.cpp_type == CPPTYPE_MESSAGE: + field_value = fields.get(field) + if field_value is None: + # Construct a new object to represent this field. + field_value = field._default_constructor(self) + fields[field] = field_value + field_value.MergeFrom(value) + else: + self._fields[field] = value cls.MergeFrom = MergeFrom def _AddMessageMethods(message_descriptor, cls): """Adds implementations of all Message methods to cls.""" _AddListFieldsMethod(message_descriptor, cls) - _AddHasFieldMethod(cls) - _AddClearFieldMethod(cls) - _AddClearExtensionMethod(cls) - _AddClearMethod(cls) - _AddHasExtensionMethod(cls) + _AddHasFieldMethod(message_descriptor, cls) + _AddClearFieldMethod(message_descriptor, cls) + if message_descriptor.is_extendable: + _AddClearExtensionMethod(cls) + _AddHasExtensionMethod(cls) + _AddClearMethod(message_descriptor, cls) _AddEqualsMethod(message_descriptor, cls) _AddStrMethod(message_descriptor, cls) _AddSetListenerMethod(cls) @@ -1304,31 +971,30 @@ def _AddMessageMethods(message_descriptor, cls): _AddSerializeToStringMethod(message_descriptor, cls) _AddSerializePartialToStringMethod(message_descriptor, cls) _AddMergeFromStringMethod(message_descriptor, cls) - _AddIsInitializedMethod(cls) + _AddIsInitializedMethod(message_descriptor, cls) _AddMergeFromMethod(cls) def _AddPrivateHelperMethods(cls): """Adds implementation of private helper methods to cls.""" - def MaybeCallTransitionToNonemptyCallback(self): - """Calls self._listener.TransitionToNonempty() the first time this - method is called. On all subsequent calls, this is a no-op. - """ - if not self._called_transition_to_nonempty: - self._listener.TransitionToNonempty() - self._called_transition_to_nonempty = True - cls._MaybeCallTransitionToNonemptyCallback = ( - MaybeCallTransitionToNonemptyCallback) - - def MarkByteSizeDirty(self): + def Modified(self): """Sets the _cached_byte_size_dirty bit to true, and propagates this to our listener iff this was a state change. """ + + # Note: Some callers check _cached_byte_size_dirty before calling + # _Modified() as an extra optimization. So, if this method is ever + # changed such that it does stuff even when _cached_byte_size_dirty is + # already true, the callers need to be updated. if not self._cached_byte_size_dirty: self._cached_byte_size_dirty = True - self._listener.ByteSizeDirty() - cls._MarkByteSizeDirty = MarkByteSizeDirty + self._listener_for_children.dirty = True + self._is_present_in_parent = True + self._listener.Modified() + + cls._Modified = Modified + cls.SetInParent = Modified class _Listener(object): @@ -1338,22 +1004,17 @@ class _Listener(object): In order to support semantics like: - foo.bar.baz = 23 + foo.bar.baz.qux = 23 assert foo.HasField('bar') ...child objects must have back references to their parents. This helper class is at the heart of this support. """ - def __init__(self, parent_message, has_field_name): + def __init__(self, parent_message): """Args: - parent_message: The message whose _MaybeCallTransitionToNonemptyCallback() - and _MarkByteSizeDirty() methods we should call when we receive - TransitionToNonempty() and ByteSizeDirty() messages. - has_field_name: The name of the "has" field that we should set in - the parent message when we receive a TransitionToNonempty message, - or None if there's no "has" field to set. (This will be the case - for child objects in "repeated" fields). + parent_message: The message whose _Modified() method we should call when + we receive Modified() messages. """ # This listener establishes a back reference from a child (contained) object # to its parent (containing) object. We make this a weak reference to avoid @@ -1363,36 +1024,27 @@ class _Listener(object): self._parent_message_weakref = parent_message else: self._parent_message_weakref = weakref.proxy(parent_message) - self._has_field_name = has_field_name - def TransitionToNonempty(self): + # As an optimization, we also indicate directly on the listener whether + # or not the parent message is dirty. This way we can avoid traversing + # up the tree in the common case. + self.dirty = False + + def Modified(self): + if self.dirty: + return try: - if self._has_field_name is not None: - setattr(self._parent_message_weakref, self._has_field_name, True) # Propagate the signal to our parents iff this is the first field set. - self._parent_message_weakref._MaybeCallTransitionToNonemptyCallback() + self._parent_message_weakref._Modified() except ReferenceError: # We can get here if a client has kept a reference to a child object, # and is now setting a field on it, but the child's parent has been # garbage-collected. This is not an error. pass - def ByteSizeDirty(self): - try: - self._parent_message_weakref._MarkByteSizeDirty() - except ReferenceError: - # Same as above. - pass - # TODO(robinson): Move elsewhere? This file is getting pretty ridiculous... # TODO(robinson): Unify error handling of "unknown extension" crap. -# TODO(robinson): There's so much similarity between the way that -# extensions behave and the way that normal fields behave that it would -# be really nice to unify more code. It's not immediately obvious -# how to do this, though, and I'd rather get the full functionality -# implemented (and, crucially, get all the tests and specs fleshed out -# and passing), and then come back to this thorny unification problem. # TODO(robinson): Support iteritems()-style iteration over all # extensions with the "has" bits turned on? class _ExtensionDict(object): @@ -1404,250 +1056,85 @@ class _ExtensionDict(object): FieldDescriptors. """ - class _ExtensionListener(object): + def __init__(self, extended_message): + """extended_message: Message instance for which we are the Extensions dict. + """ - """Adapts an _ExtensionDict to behave as a MessageListener.""" + self._extended_message = extended_message - def __init__(self, extension_dict, handle_id): - self._extension_dict = extension_dict - self._handle_id = handle_id + def __getitem__(self, extension_handle): + """Returns the current value of the given extension handle.""" - def TransitionToNonempty(self): - self._extension_dict._SubmessageTransitionedToNonempty(self._handle_id) + _VerifyExtensionHandle(self._extended_message, extension_handle) - def ByteSizeDirty(self): - self._extension_dict._SubmessageByteSizeBecameDirty() + result = self._extended_message._fields.get(extension_handle) + if result is not None: + return result - # TODO(robinson): Somewhere, we need to blow up if people - # try to register two extensions with the same field number. - # (And we need a test for this of course). + if extension_handle.label == _FieldDescriptor.LABEL_REPEATED: + result = extension_handle._default_constructor(self._extended_message) + elif extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: + result = extension_handle.message_type._concrete_class() + try: + result._SetListener(self._extended_message._listener_for_children) + except ReferenceError: + pass + else: + # Singular scalar -- just return the default without inserting into the + # dict. + return extension_handle.default_value - def __init__(self, extended_message, known_extensions): - """extended_message: Message instance for which we are the Extensions dict. - known_extensions: Iterable of known extension handles. - These must be FieldDescriptors. - """ - # We keep a weak reference to extended_message, since - # it has a reference to this instance in turn. - self._extended_message = weakref.proxy(extended_message) - # We make a deep copy of known_extensions to avoid any - # thread-safety concerns, since the argument passed in - # is the global (class-level) dict of known extensions for - # this type of message, which could be modified at any time - # via a RegisterExtension() call. - # - # This dict maps from handle id to handle (a FieldDescriptor). - # - # XXX - # TODO(robinson): This isn't good enough. The client could - # instantiate an object in module A, then afterward import - # module B and pass the instance to B.Foo(). If B imports - # an extender of this proto and then tries to use it, B - # will get a KeyError, even though the extension *is* registered - # at the time of use. - # XXX - self._known_extensions = dict((id(e), e) for e in known_extensions) - # Read lock around self._values, which may be modified by multiple - # concurrent readers in the conceptually "const" __getitem__ method. - # So, we grab this lock in every "read-only" method to ensure - # that concurrent read access is safe without external locking. - self._lock = threading.Lock() - # Maps from extension handle ID to current value of that extension. - self._values = {} - # Maps from extension handle ID to a boolean "has" bit, but only - # for non-repeated extension fields. - keys = (id for id, extension in self._known_extensions.iteritems() - if extension.label != _FieldDescriptor.LABEL_REPEATED) - self._has_bits = dict.fromkeys(keys, False) - - 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 + # Atomically check if another thread has preempted us and, if not, swap + # in the new object we just created. If someone has preempted us, we + # take that object and discard ours. + # WARNING: We are relying on setdefault() being atomic. This is true + # in CPython but we haven't investigated others. This warning appears + # in several other locations in this file. + result = self._extended_message._fields.setdefault( + extension_handle, result) - def __getitem__(self, extension_handle): - """Returns the current value of the given extension handle.""" - # We don't care as much about keeping critical sections short in the - # extension support, since it's presumably much less of a common case. - self._lock.acquire() - try: - handle_id = id(extension_handle) - if handle_id not in self._known_extensions: - raise KeyError('Extension not known to this class') - if handle_id not in self._values: - self._AddMissingHandle(extension_handle, handle_id) - return self._values[handle_id] - finally: - self._lock.release() + return result def __eq__(self, other): - # We have to grab read locks since we're accessing _values - # in a "const" method. See the comment in the constructor. - if self is other: - return True - self._lock.acquire() - try: - other._lock.acquire() - try: - if self._has_bits != other._has_bits: - return False - # If there's a "has" bit, then only compare values where it is true. - for k, v in self._values.iteritems(): - if self._has_bits.get(k, False) and v != other._values[k]: - return False - return True - finally: - other._lock.release() - finally: - self._lock.release() + if not isinstance(other, self.__class__): + return False + + my_fields = self._extended_message.ListFields() + other_fields = other._extended_message.ListFields() + + # Get rid of non-extension fields. + my_fields = [ field for field in my_fields if field.is_extension ] + other_fields = [ field for field in other_fields if field.is_extension ] + + return my_fields == other_fields def __ne__(self, other): return not self == other # Note that this is only meaningful for non-repeated, scalar extension - # fields. Note also that we may have to call - # MaybeCallTransitionToNonemptyCallback() when we do successfully set a field - # this way, to set any necssary "has" bits in the ancestors of the extended - # message. + # fields. Note also that we may have to call _Modified() when we do + # successfully set a field this way, to set any necssary "has" bits in the + # ancestors of the extended message. def __setitem__(self, extension_handle, value): """If extension_handle specifies a non-repeated, scalar extension field, sets the value of that field. """ - handle_id = id(extension_handle) - if handle_id not in self._known_extensions: - raise KeyError('Extension not known to this class') - field = extension_handle # Just shorten the name. - if (field.label == _FieldDescriptor.LABEL_OPTIONAL - and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE): - # It's slightly wasteful to lookup the type checker each time, - # but we expect this to be a vanishingly uncommon case anyway. - type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type) - type_checker.CheckValue(value) - self._values[handle_id] = value - self._has_bits[handle_id] = True - self._extended_message._MarkByteSizeDirty() - self._extended_message._MaybeCallTransitionToNonemptyCallback() - else: - raise TypeError('Extension is repeated and/or a composite type.') - - def _AddMissingHandle(self, extension_handle, handle_id): - """Helper internal to ExtensionDict.""" - # Special handling for non-repeated message extensions, which (like - # normal fields of this kind) are initialized lazily. - # REQUIRES: _lock already held. - cpp_type = extension_handle.cpp_type - label = extension_handle.label - if (cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE - and label != _FieldDescriptor.LABEL_REPEATED): - self._AddMissingNonRepeatedCompositeHandle(extension_handle, handle_id) - else: - self._values[handle_id] = _DefaultValueForField( - self._extended_message, extension_handle) - - def _AddMissingNonRepeatedCompositeHandle(self, extension_handle, handle_id): - """Helper internal to ExtensionDict.""" - # REQUIRES: _lock already held. - value = extension_handle.message_type._concrete_class() - value._SetListener(_ExtensionDict._ExtensionListener(self, handle_id)) - self._values[handle_id] = value - - def _SubmessageTransitionedToNonempty(self, handle_id): - """Called when a submessage with a given handle id first transitions to - being nonempty. Called by _ExtensionListener. - """ - assert handle_id in self._has_bits - self._has_bits[handle_id] = True - self._extended_message._MaybeCallTransitionToNonemptyCallback() - def _SubmessageByteSizeBecameDirty(self): - """Called whenever a submessage's cached byte size becomes invalid - (goes from being "clean" to being "dirty"). Called by _ExtensionListener. - """ - self._extended_message._MarkByteSizeDirty() - - # We may wish to widen the public interface of Message.Extensions - # to expose some of this private functionality in the future. - # For now, we make all this functionality module-private and just - # implement what we need for serialization/deserialization, - # HasField()/ClearField(), etc. - - def _HasExtension(self, extension_handle): - """Method for internal use by this module. - Returns true iff we "have" this extension in the sense of the - "has" bit being set. - """ - handle_id = id(extension_handle) - # Note that this is different from the other checks. - if handle_id not in self._has_bits: - raise KeyError('Extension not known to this class, or is repeated field.') - return self._has_bits[handle_id] - - # Intentionally pretty similar to ClearField() above. - def _ClearExtension(self, extension_handle): - """Method for internal use by this module. - Clears the specified extension, unsetting its "has" bit. - """ - handle_id = id(extension_handle) - if handle_id not in self._known_extensions: - raise KeyError('Extension not known to this class') - default_value = _DefaultValueForField(self._extended_message, - extension_handle) - if extension_handle.label == _FieldDescriptor.LABEL_REPEATED: - self._extended_message._MarkByteSizeDirty() - else: - cpp_type = extension_handle.cpp_type - if cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - if handle_id in self._values: - # Future modifications to this object shouldn't set any - # "has" bits here. - self._values[handle_id]._SetListener(None) - if self._has_bits[handle_id]: - self._has_bits[handle_id] = False - self._extended_message._MarkByteSizeDirty() - if handle_id in self._values: - del self._values[handle_id] - - def _ListSetExtensions(self): - """Method for internal use by this module. - - Returns an sequence of all extensions that are currently "set" - in this extension dict. A "set" extension is a repeated extension, - or a non-repeated extension with its "has" bit set. - - The returned sequence contains (field_descriptor, value) pairs, - where value is the current value of the extension with the given - field descriptor. - - The sequence values are in arbitrary order. - """ - self._lock.acquire() # Read-only methods must lock around self._values. - try: - set_extensions = [] - for handle_id, value in self._values.iteritems(): - handle = self._known_extensions[handle_id] - if (handle.label == _FieldDescriptor.LABEL_REPEATED - or self._has_bits[handle_id]): - set_extensions.append((handle, value)) - return set_extensions - finally: - self._lock.release() - - def _AllExtensionsByNumber(self): - """Method for internal use by this module. - - Returns: A dict mapping field_number to (handle, field_descriptor), - for *all* registered extensions for this dict. - """ - return self._extensions_by_number + _VerifyExtensionHandle(self._extended_message, extension_handle) + + if (extension_handle.label == _FieldDescriptor.LABEL_REPEATED or + extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE): + raise TypeError( + 'Cannot assign to extension "%s" because it is a repeated or ' + 'composite type.' % extension_handle.full_name) + + # It's slightly wasteful to lookup the type checker each time, + # but we expect this to be a vanishingly uncommon case anyway. + type_checker = type_checkers.GetTypeChecker( + extension_handle.cpp_type, extension_handle.type) + type_checker.CheckValue(value) + self._extended_message._fields[extension_handle] = value + self._extended_message._Modified() def _FindExtensionByName(self, name): """Tries to find a known extension with the specified name. @@ -1658,4 +1145,4 @@ class _ExtensionDict(object): Returns: Extension field descriptor. """ - return self._extensions_by_name.get(name, None) + return self._extended_message._extensions_by_name.get(name, None) diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index 1cddce6c..889aa836 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -149,6 +149,10 @@ def _MergeField(tokenizer, message): name.append(tokenizer.ConsumeIdentifier()) name = '.'.join(name) + if not message_descriptor.is_extendable: + raise tokenizer.ParseErrorPreviousToken( + 'Message type "%s" does not have extensions.' % + message_descriptor.full_name) field = message.Extensions._FindExtensionByName(name) if not field: raise tokenizer.ParseErrorPreviousToken( @@ -198,6 +202,7 @@ def _MergeField(tokenizer, message): sub_message = message.Extensions[field] else: sub_message = getattr(message, field.name) + sub_message.SetInParent() while not tokenizer.TryConsume(end_token): if tokenizer.AtEnd(): diff --git a/python/setup.py b/python/setup.py index 118ccd41..4051c533 100755 --- a/python/setup.py +++ b/python/setup.py @@ -58,16 +58,13 @@ def MakeTestSuite(): generate_proto("../src/google/protobuf/unittest.proto") generate_proto("../src/google/protobuf/unittest_import.proto") generate_proto("../src/google/protobuf/unittest_mset.proto") + generate_proto("../src/google/protobuf/unittest_no_generic_services.proto") generate_proto("google/protobuf/internal/more_extensions.proto") generate_proto("google/protobuf/internal/more_messages.proto") import unittest import google.protobuf.internal.generator_test as generator_test - import google.protobuf.internal.decoder_test as decoder_test import google.protobuf.internal.descriptor_test as descriptor_test - import google.protobuf.internal.encoder_test as encoder_test - import google.protobuf.internal.input_stream_test as input_stream_test - import google.protobuf.internal.output_stream_test as output_stream_test import google.protobuf.internal.reflection_test as reflection_test import google.protobuf.internal.service_reflection_test \ as service_reflection_test @@ -77,11 +74,7 @@ def MakeTestSuite(): loader = unittest.defaultTestLoader suite = unittest.TestSuite() for test in [ generator_test, - decoder_test, descriptor_test, - encoder_test, - input_stream_test, - output_stream_test, reflection_test, service_reflection_test, text_format_test, @@ -114,9 +107,7 @@ if __name__ == '__main__': 'google.protobuf.internal.containers', 'google.protobuf.internal.decoder', 'google.protobuf.internal.encoder', - 'google.protobuf.internal.input_stream', 'google.protobuf.internal.message_listener', - 'google.protobuf.internal.output_stream', 'google.protobuf.internal.type_checkers', 'google.protobuf.internal.wire_format', 'google.protobuf.descriptor', diff --git a/src/Makefile.am b/src/Makefile.am index 53da6f1e..510613ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,8 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS) # If I say "dist_include_DATA", automake complains that $(includedir) is not # a "legitimate" directory for DATA. Screw you, automake. protodir = $(includedir) -nobase_dist_proto_DATA = google/protobuf/descriptor.proto +nobase_dist_proto_DATA = google/protobuf/descriptor.proto \ + google/protobuf/compiler/plugin.proto # Not sure why these don't get cleaned automatically. clean-local: @@ -66,6 +67,8 @@ nobase_include_HEADERS = \ google/protobuf/compiler/command_line_interface.h \ google/protobuf/compiler/importer.h \ google/protobuf/compiler/parser.h \ + google/protobuf/compiler/plugin.h \ + google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ google/protobuf/compiler/java/java_generator.h \ google/protobuf/compiler/python/python_generator.h @@ -87,6 +90,7 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/repeated_field.cc \ google/protobuf/wire_format_lite.cc \ google/protobuf/io/coded_stream.cc \ + google/protobuf/io/coded_stream_inl.h \ google/protobuf/io/zero_copy_stream.cc \ google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -123,6 +127,10 @@ libprotoc_la_LDFLAGS = -version-info 5:0:0 libprotoc_la_SOURCES = \ google/protobuf/compiler/code_generator.cc \ google/protobuf/compiler/command_line_interface.cc \ + google/protobuf/compiler/plugin.cc \ + google/protobuf/compiler/plugin.pb.cc \ + google/protobuf/compiler/subprocess.cc \ + google/protobuf/compiler/subprocess.h \ google/protobuf/compiler/cpp/cpp_enum.cc \ google/protobuf/compiler/cpp/cpp_enum.h \ google/protobuf/compiler/cpp/cpp_enum_field.cc \ @@ -186,6 +194,7 @@ protoc_inputs = \ google/protobuf/unittest_lite.proto \ google/protobuf/unittest_import_lite.proto \ google/protobuf/unittest_lite_imports_nonlite.proto \ + google/protobuf/unittest_no_generic_services.proto \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto EXTRA_DIST = \ @@ -226,6 +235,8 @@ protoc_outputs = \ 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/unittest_no_generic_services.pb.cc \ + google/protobuf/unittest_no_generic_services.pb.h \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h @@ -265,7 +276,7 @@ COMMON_TEST_SOURCES = \ google/protobuf/testing/file.cc \ google/protobuf/testing/file.h -check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZCHECKPROGRAMS) +check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test test_plugin $(GZCHECKPROGRAMS) protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ $(top_builddir)/gtest/lib/libgtest.la \ $(top_builddir)/gtest/lib/libgtest_main.la @@ -297,9 +308,14 @@ protobuf_test_SOURCES = \ google/protobuf/io/zero_copy_stream_unittest.cc \ google/protobuf/compiler/command_line_interface_unittest.cc \ google/protobuf/compiler/importer_unittest.cc \ + google/protobuf/compiler/mock_code_generator.cc \ + google/protobuf/compiler/mock_code_generator.h \ google/protobuf/compiler/parser_unittest.cc \ google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc \ google/protobuf/compiler/cpp/cpp_unittest.cc \ + google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \ + google/protobuf/compiler/java/java_plugin_unittest.cc \ + google/protobuf/compiler/python/python_plugin_unittest.cc \ $(COMMON_TEST_SOURCES) nodist_protobuf_test_SOURCES = $(protoc_outputs) @@ -325,6 +341,15 @@ protobuf_lite_test_SOURCES = \ google/protobuf/test_util_lite.h nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs) +# Test plugin binary. +test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ + $(top_builddir)/gtest/lib/libgtest.la +test_plugin_SOURCES = \ + google/protobuf/compiler/mock_code_generator.cc \ + google/protobuf/testing/file.cc \ + google/protobuf/testing/file.h \ + google/protobuf/compiler/test_plugin.cc + if HAVE_ZLIB zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0def84d8..3413a36a 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include +#include #include namespace google { @@ -43,9 +44,15 @@ namespace compiler { CodeGenerator::~CodeGenerator() {} OutputDirectory::~OutputDirectory() {} +io::ZeroCopyOutputStream* OutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + GOOGLE_LOG(FATAL) << "This OutputDirectory does not support insertion."; + return NULL; // make compiler happy +} + // Parses a set of comma-delimited name/value pairs. void ParseGeneratorParameter(const string& text, - vector >* output) { + vector >* output) { vector parts; SplitStringUsing(text, ",", &parts); diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index 8a7081f7..47ebb4d2 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -103,6 +103,13 @@ class LIBPROTOC_EXPORT OutputDirectory { // contain "." or ".." components. virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0; + // Creates a ZeroCopyOutputStream which will insert code into the given file + // at the given insertion point. See plugin.proto for more information on + // insertion points. The default implementation assert-fails -- it exists + // only for backwards-compatibility. + virtual io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory); }; @@ -114,7 +121,7 @@ class LIBPROTOC_EXPORT OutputDirectory { // parses to the pairs: // ("foo", "bar"), ("baz", ""), ("qux", "corge") extern void ParseGeneratorParameter(const string&, - vector >*); + vector >*); } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 3eba3486..39bd370e 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -32,6 +32,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #include @@ -46,15 +48,19 @@ #include #include -#include #include #include +#include +#include #include #include #include #include +#include #include #include +#include +#include namespace google { @@ -182,6 +188,8 @@ class CommandLineInterface::DiskOutputDirectory : public OutputDirectory { // implements OutputDirectory -------------------------------------- io::ZeroCopyOutputStream* Open(const string& filename); + io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); private: string root_; @@ -209,11 +217,45 @@ class CommandLineInterface::ErrorReportingFileOutput private: scoped_ptr file_stream_; - int file_descriptor_; string filename_; DiskOutputDirectory* directory_; }; +// Kind of like ErrorReportingFileOutput, but used when inserting +// (OutputDirectory::OpenForInsert()). In this case, we are writing to a +// temporary file, since we must copy data from the original. We copy the +// data up to the insertion point in the constructor, and the remainder in the +// destructor. We then replace the original file with the temporary, also in +// the destructor. +class CommandLineInterface::InsertionOutputStream + : public io::ZeroCopyOutputStream { + public: + InsertionOutputStream( + const string& filename, + const string& temp_filename, + const string& insertion_point, + int original_file_descriptor, // Takes ownership. + int temp_file_descriptor, // Takes ownership. + DiskOutputDirectory* directory); // Does not take ownership. + ~InsertionOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size) { return temp_file_->Next(data, size); } + void BackUp(int count) { temp_file_->BackUp(count); } + int64 ByteCount() const { return temp_file_->ByteCount(); } + + private: + scoped_ptr original_file_; + scoped_ptr temp_file_; + + string filename_; + string temp_filename_; + DiskOutputDirectory* directory_; + + // The contents of the line containing the insertion point. + string magic_line_; +}; + // ------------------------------------------------------------------- CommandLineInterface::DiskOutputDirectory::DiskOutputDirectory( @@ -242,6 +284,8 @@ bool CommandLineInterface::DiskOutputDirectory::VerifyExistence() { return true; } +// ------------------------------------------------------------------- + io::ZeroCopyOutputStream* CommandLineInterface::DiskOutputDirectory::Open( const string& filename) { // Recursively create parent directories to the output file. @@ -286,7 +330,6 @@ CommandLineInterface::ErrorReportingFileOutput::ErrorReportingFileOutput( const string& filename, DiskOutputDirectory* directory) : file_stream_(new io::FileOutputStream(file_descriptor)), - file_descriptor_(file_descriptor), filename_(filename), directory_(directory) {} @@ -304,6 +347,201 @@ CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() { } } +// ------------------------------------------------------------------- + +io::ZeroCopyOutputStream* +CommandLineInterface::DiskOutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + string path = root_ + filename; + + // Put the temp file in the same directory so that we can simply rename() it + // into place later. + string temp_path = path + ".protoc_temp"; + + // Open the original file. + int original_file; + do { + original_file = open(path.c_str(), O_RDONLY | O_BINARY); + } while (original_file < 0 && errno == EINTR); + + if (original_file < 0) { + // Failed to open. + cerr << path << ": " << strerror(errno) << endl; + had_error_ = true; + // Return a dummy stream. + return new io::ArrayOutputStream(NULL, 0); + } + + // Create the temp file. + int temp_file; + do { + temp_file = + open(temp_path.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (temp_file < 0 && errno == EINTR); + + if (temp_file < 0) { + // Failed to open. + cerr << temp_path << ": " << strerror(errno) << endl; + had_error_ = true; + close(original_file); + // Return a dummy stream. + return new io::ArrayOutputStream(NULL, 0); + } + + return new InsertionOutputStream( + path, temp_path, insertion_point, original_file, temp_file, this); +} + +namespace { + +// Helper for reading lines from a ZeroCopyInputStream. +// TODO(kenton): Put somewhere reusable? +class LineReader { + public: + LineReader(io::ZeroCopyInputStream* input) + : input_(input), buffer_(NULL), size_(0) {} + + ~LineReader() { + if (size_ > 0) { + input_->BackUp(size_); + } + } + + bool ReadLine(string* line) { + line->clear(); + + while (true) { + for (int i = 0; i < size_; i++) { + if (buffer_[i] == '\n') { + line->append(buffer_, i + 1); + buffer_ += i + 1; + size_ -= i + 1; + return true; + } + } + + line->append(buffer_, size_); + + const void* void_buffer; + if (!input_->Next(&void_buffer, &size_)) { + buffer_ = NULL; + size_ = 0; + return false; + } + + buffer_ = reinterpret_cast(void_buffer); + } + } + + private: + io::ZeroCopyInputStream* input_; + const char* buffer_; + int size_; +}; + +} // namespace + +CommandLineInterface::InsertionOutputStream::InsertionOutputStream( + const string& filename, + const string& temp_filename, + const string& insertion_point, + int original_file_descriptor, + int temp_file_descriptor, + DiskOutputDirectory* directory) + : original_file_(new io::FileInputStream(original_file_descriptor)), + temp_file_(new io::FileOutputStream(temp_file_descriptor)), + filename_(filename), + temp_filename_(temp_filename), + directory_(directory) { + string magic_string = strings::Substitute( + "@@protoc_insertion_point($0)", insertion_point); + + LineReader reader(original_file_.get()); + io::Printer writer(temp_file_.get(), '$'); + string line; + + while (true) { + if (!reader.ReadLine(&line)) { + int error = temp_file_->GetErrno(); + if (error == 0) { + cerr << filename << ": Insertion point not found: " + << insertion_point << endl; + } else { + cerr << filename << ": " << strerror(error) << endl; + } + original_file_->Close(); + original_file_.reset(); + // Will finish handling error in the destructor. + break; + } + + if (line.find(magic_string) != string::npos) { + // Found the magic line. Since we want to insert before it, save it for + // later. + magic_line_ = line; + break; + } + + writer.PrintRaw(line); + } +} + +CommandLineInterface::InsertionOutputStream::~InsertionOutputStream() { + // C-style error handling is teh best. + bool had_error = false; + + if (original_file_ == NULL) { + // We had an error in the constructor. + had_error = true; + } else { + // Use CodedOutputStream for convenience, so we don't have to deal with + // copying buffers ourselves. + io::CodedOutputStream out(temp_file_.get()); + out.WriteRaw(magic_line_.data(), magic_line_.size()); + + // Write the rest of the original file. + const void* buffer; + int size; + while (original_file_->Next(&buffer, &size)) { + out.WriteRaw(buffer, size); + } + + // Close the original file. + if (!original_file_->Close()) { + cerr << filename_ << ": " << strerror(original_file_->GetErrno()) << endl; + had_error = true; + } + } + + // Check if we had any errors while writing. + if (temp_file_->GetErrno() != 0) { + cerr << filename_ << ": " << strerror(temp_file_->GetErrno()) << endl; + had_error = true; + } + + // Close the temp file. + if (!temp_file_->Close()) { + cerr << filename_ << ": " << strerror(temp_file_->GetErrno()) << endl; + had_error = true; + } + + // If everything was successful, overwrite the original file with the temp + // file. + if (!had_error) { + if (rename(temp_filename_.c_str(), filename_.c_str()) < 0) { + cerr << filename_ << ": rename: " << strerror(errno) << endl; + had_error = true; + } + } + + if (had_error) { + // We had some sort of error so let's try to delete the temp file. + remove(temp_filename_.c_str()); + directory_->set_had_error(true); + } +} + // =================================================================== CommandLineInterface::CommandLineInterface() @@ -323,6 +561,10 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name, generators_[flag_name] = info; } +void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) { + plugin_prefix_ = exe_name_prefix; +} + int CommandLineInterface::Run(int argc, const char* const argv[]) { Clear(); if (!ParseArguments(argc, argv)) return 1; @@ -346,7 +588,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { vector parsed_files; - // Parse each file and generate output. + // Parse each file. for (int i = 0; i < input_files_.size(); i++) { // Import the file. const FileDescriptor* parsed_file = importer.Import(input_files_[i]); @@ -359,13 +601,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { "--disallow_services was used." << endl; return 1; } + } - if (mode_ == MODE_COMPILE) { - // Generate output files. - for (int i = 0; i < output_directives_.size(); i++) { - if (!GenerateOutput(parsed_file, output_directives_[i])) { - return 1; - } + // Generate output. + if (mode_ == MODE_COMPILE) { + for (int i = 0; i < output_directives_.size(); i++) { + if (!GenerateOutput(parsed_files, output_directives_[i])) { + return 1; } } } @@ -686,10 +928,37 @@ bool CommandLineInterface::InterpretArgument(const string& name, return false; } + } else if (name == "--plugin") { + if (plugin_prefix_.empty()) { + cerr << "This compiler does not support plugins." << endl; + return false; + } + + string name; + string path; + + string::size_type equals_pos = value.find_first_of('='); + if (equals_pos == string::npos) { + // Use the basename of the file. + string::size_type slash_pos = value.find_last_of('/'); + if (slash_pos == string::npos) { + name = value; + } else { + name = value.substr(slash_pos + 1); + } + path = value; + } else { + name = value.substr(0, equals_pos); + path = value.substr(equals_pos + 1); + } + + plugins_[name] = path; + } else { // Some other flag. Look it up in the generators list. - GeneratorMap::const_iterator iter = generators_.find(name); - if (iter == generators_.end()) { + const GeneratorInfo* generator_info = FindOrNull(generators_, name); + if (generator_info == NULL && + (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { cerr << "Unknown flag: " << name << endl; return false; } @@ -703,7 +972,11 @@ bool CommandLineInterface::InterpretArgument(const string& name, OutputDirective directive; directive.name = name; - directive.generator = iter->second.generator; + if (generator_info == NULL) { + directive.generator = NULL; + } else { + directive.generator = generator_info->generator; + } // Split value at ':' to separate the generator parameter from the // filename. However, avoid doing this if the colon is part of a valid @@ -755,6 +1028,17 @@ void CommandLineInterface::PrintHelpText() { " --error_format=FORMAT Set the format in which to print errors.\n" " FORMAT may be 'gcc' (the default) or 'msvs'\n" " (Microsoft Visual Studio format)." << endl; + if (!plugin_prefix_.empty()) { + cerr << +" --plugin=EXECUTABLE Specifies a plugin executable to use.\n" +" Normally, protoc searches the PATH for\n" +" plugins, but you may specify additional\n" +" executables not in the path using this flag.\n" +" Additionally, EXECUTABLE may be of the form\n" +" NAME=PATH, in which case the given plugin name\n" +" is mapped to the given executable even if\n" +" the executable's own name differs." << endl; + } for (GeneratorMap::iterator iter = generators_.begin(); iter != generators_.end(); ++iter) { @@ -768,7 +1052,7 @@ void CommandLineInterface::PrintHelpText() { } bool CommandLineInterface::GenerateOutput( - const FileDescriptor* parsed_file, + const vector& parsed_files, const OutputDirective& output_directive) { // Create the output directory. DiskOutputDirectory output_directory(output_directive.output_location); @@ -780,12 +1064,34 @@ bool CommandLineInterface::GenerateOutput( // Call the generator. string error; - if (!output_directive.generator->Generate( - parsed_file, output_directive.parameter, &output_directory, &error)) { - // Generator returned an error. - cerr << parsed_file->name() << ": " << output_directive.name << ": " - << error << endl; - return false; + if (output_directive.generator == NULL) { + // This is a plugin. + GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && + HasSuffixString(output_directive.name, "_out")) + << "Bad name for plugin generator: " << output_directive.name; + + // Strip the "--" and "_out" and add the plugin prefix. + string plugin_name = plugin_prefix_ + "gen-" + + output_directive.name.substr(2, output_directive.name.size() - 6); + + if (!GeneratePluginOutput(parsed_files, plugin_name, + output_directive.parameter, + &output_directory, &error)) { + cerr << output_directive.name << ": " << error << endl; + return false; + } + } else { + // Regular generator. + for (int i = 0; i < parsed_files.size(); i++) { + if (!output_directive.generator->Generate( + parsed_files[i], output_directive.parameter, + &output_directory, &error)) { + // Generator returned an error. + cerr << output_directive.name << ": " << parsed_files[i]->name() << ": " + << error << endl; + return false; + } + } } // Check for write errors. @@ -796,6 +1102,84 @@ bool CommandLineInterface::GenerateOutput( return true; } +bool CommandLineInterface::GeneratePluginOutput( + const vector& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error) { + CodeGeneratorRequest request; + CodeGeneratorResponse response; + + // Build the request. + if (!parameter.empty()) { + request.set_parameter(parameter); + } + + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + request.add_file_to_generate(parsed_files[i]->name()); + GetTransitiveDependencies(parsed_files[i], &already_seen, + request.mutable_proto_file()); + } + + // Invoke the plugin. + Subprocess subprocess; + + if (plugins_.count(plugin_name) > 0) { + subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME); + } else { + subprocess.Start(plugin_name, Subprocess::SEARCH_PATH); + } + + string communicate_error; + if (!subprocess.Communicate(request, &response, &communicate_error)) { + *error = strings::Substitute("$0: $1", plugin_name, communicate_error); + return false; + } + + // Write the files. We do this even if there was a generator error in order + // to match the behavior of a compiled-in generator. + scoped_ptr current_output; + for (int i = 0; i < response.file_size(); i++) { + const CodeGeneratorResponse::File& output_file = response.file(i); + + if (!output_file.insertion_point().empty()) { + // Open a file for insert. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->OpenForInsert( + output_file.name(), output_file.insertion_point())); + } else if (!output_file.name().empty()) { + // Starting a new file. Open it. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->Open(output_file.name())); + } else if (current_output == NULL) { + *error = strings::Substitute( + "$0: First file chunk returned by plugin did not specify a file name.", + plugin_name); + return false; + } + + // Use CodedOutputStream for convenience; otherwise we'd need to provide + // our own buffer-copying loop. + io::CodedOutputStream writer(current_output.get()); + writer.WriteString(output_file.content()); + } + + // Check for errors. + if (!response.error().empty()) { + // Generator returned an error. + *error = response.error(); + return false; + } + + return true; +} + bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { // Look up the type. const Descriptor* type = pool->FindMessageTypeByName(codec_type_); @@ -862,22 +1246,16 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { bool CommandLineInterface::WriteDescriptorSet( const vector parsed_files) { FileDescriptorSet file_set; - set already_added; - vector to_add(parsed_files); - - while (!to_add.empty()) { - const FileDescriptor* file = to_add.back(); - to_add.pop_back(); - if (already_added.insert(file).second) { - // This file was not already in the set. - file->CopyTo(file_set.add_file()); - - if (imports_in_descriptor_set_) { - // Add all of this file's dependencies. - for (int i = 0; i < file->dependency_count(); i++) { - to_add.push_back(file->dependency(i)); - } - } + + if (imports_in_descriptor_set_) { + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies( + parsed_files[i], &already_seen, file_set.mutable_file()); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + parsed_files[i]->CopyTo(file_set.add_file()); } } @@ -906,6 +1284,24 @@ bool CommandLineInterface::WriteDescriptorSet( return true; } +void CommandLineInterface::GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output) { + if (!already_seen->insert(file).second) { + // Already saw this file. Skip. + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + GetTransitiveDependencies(file->dependency(i), already_seen, output); + } + + // Add this file. + file->CopyTo(output->Add()); +} + } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index ec658636..1070a83b 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -50,10 +50,13 @@ namespace protobuf { class FileDescriptor; // descriptor.h class DescriptorPool; // descriptor.h +class FileDescriptorProto; // descriptor.pb.h +template class RepeatedPtrField; // repeated_field.h namespace compiler { class CodeGenerator; // code_generator.h +class OutputDirectory; // code_generator.h class DiskSourceTree; // importer.h // This class implements the command-line interface to the protocol compiler. @@ -109,6 +112,37 @@ class LIBPROTOC_EXPORT CommandLineInterface { CodeGenerator* generator, const string& help_text); + // Enables "plugins". In this mode, if a command-line flag ends with "_out" + // but does not match any registered generator, the compiler will attempt to + // find a "plugin" to implement the generator. Plugins are just executables. + // They should live somewhere in the PATH. + // + // The compiler determines the executable name to search for by concatenating + // exe_name_prefix with the unrecognized flag name, removing "_out". So, for + // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out, + // the compiler will try to run the program "protoc-foo". + // + // The plugin program should implement the following usage: + // plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS + // --out indicates the output directory (as passed to the --foo_out + // parameter); if omitted, the current directory should be used. --parameter + // gives the generator parameter, if any was provided. The PROTO_FILES list + // the .proto files which were given on the compiler command-line; these are + // the files for which the plugin is expected to generate output code. + // Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in + // descriptor.proto). This is piped to the plugin's stdin. The set will + // include descriptors for all the files listed in PROTO_FILES as well as + // all files that they import. The plugin MUST NOT attempt to read the + // PROTO_FILES directly -- it must use the FileDescriptorSet. + // + // The plugin should generate whatever files are necessary, as code generators + // normally do. It should write the names of all files it generates to + // stdout. The names should be relative to the output directory, NOT absolute + // names or relative to the current directory. If any errors occur, error + // messages should be written to stderr. If an error is fatal, the plugin + // should exit with a non-zero exit code. + void AllowPlugins(const string& exe_name_prefix); + // Run the Protocol Compiler with the given command-line parameters. // Returns the error code which should be returned by main(). // @@ -142,6 +176,7 @@ class LIBPROTOC_EXPORT CommandLineInterface { class ErrorPrinter; class DiskOutputDirectory; class ErrorReportingFileOutput; + class InsertionOutputStream; // Clear state from previous Run(). void Clear(); @@ -176,8 +211,13 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Generate the given output file from the given input. struct OutputDirective; // see below - bool GenerateOutput(const FileDescriptor* proto_file, + bool GenerateOutput(const vector& parsed_files, const OutputDirective& output_directive); + bool GeneratePluginOutput(const vector& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error); // Implements --encode and --decode. bool EncodeOrDecode(const DescriptorPool* pool); @@ -185,6 +225,17 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Implements the --descriptor_set_out option. bool WriteDescriptorSet(const vector parsed_files); + // Get all transitive dependencies of the given file (including the file + // itself), adding them to the given list of FileDescriptorProtos. The + // protos will be ordered such that every file is listed before any file that + // depends on it, so that you can call DescriptorPool::BuildFile() on them + // in order. Any files in *already_seen will not be added, and each file + // added will be inserted into *already_seen. + static void GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output); + // ----------------------------------------------------------------- // The name of the executable as invoked (i.e. argv[0]). @@ -201,6 +252,14 @@ class LIBPROTOC_EXPORT CommandLineInterface { typedef map GeneratorMap; GeneratorMap generators_; + // See AllowPlugins(). If this is empty, plugins aren't allowed. + string plugin_prefix_; + + // Maps specific plugin names to files. When executing a plugin, this map + // is searched first to find the plugin executable. If not found here, the + // PATH (or other OS-specific search strategy) is searched. + map plugins_; + // Stuff parsed from command line. enum Mode { MODE_COMPILE, // Normal mode: parse .proto files and compile them. @@ -223,8 +282,8 @@ class LIBPROTOC_EXPORT CommandLineInterface { // output_directives_ lists all the files we are supposed to output and what // generator to use for each. struct OutputDirective { - string name; - CodeGenerator* generator; + string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins string parameter; string output_location; }; diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 9da41c02..83850cf9 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -47,10 +47,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -83,28 +85,19 @@ class CommandLineInterfaceTest : public testing::Test { // ----------------------------------------------------------------- // Methods to set up the test (called before Run()). - class MockCodeGenerator; class NullCodeGenerator; - // Registers a MockCodeGenerator with the given name. - MockCodeGenerator* RegisterGenerator(const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text); - MockCodeGenerator* RegisterErrorGenerator(const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename, - const string& help_text); - - // Registers a CodeGenerator which will not actually generate anything, - // but records the parameter passed to the generator. - NullCodeGenerator* RegisterNullGenerator(const string& flag_name); + // Normally plugins are allowed for all tests. Call this to explicitly + // disable them. + void DisallowPlugins() { disallow_plugins_ = true; } // Create a temp file within temp_directory_ with the given name. // The containing directory is also created if necessary. void CreateTempFile(const string& name, const string& contents); + // Create a subdirectory within temp_directory_. + void CreateTempDir(const string& name); + void SetInputsAreProtoPathRelative(bool enable) { cli_.SetInputsAreProtoPathRelative(enable); } @@ -130,18 +123,28 @@ class CommandLineInterfaceTest : public testing::Test { bool HasAlternateErrorSubstring(const string& expected_substring); // Checks that MockCodeGenerator::Generate() was called in the given - // context. That is, this tests if the generator with the given name + // context (or the generator in test_plugin.cc, which produces the same + // output). That is, this tests if the generator with the given name // was called with the given parameter and proto file and produced the // given output file. This is checked by reading the output file and // checking that it contains the content that MockCodeGenerator would // generate given these inputs. message_name is the name of the first // message that appeared in the proto file; this is just to make extra // sure that the correct file was parsed. + void ExpectGenerated(const string& generator_name, + const string& parameter, + const string& proto_name, + const string& message_name); void ExpectGenerated(const string& generator_name, const string& parameter, const string& proto_name, const string& message_name, - const string& output_file); + const string& output_directory); + void ExpectGeneratedWithInsertions(const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name); void ReadDescriptorSet(const string& filename, FileDescriptorSet* descriptor_set); @@ -150,6 +153,9 @@ class CommandLineInterfaceTest : public testing::Test { // The object we are testing. CommandLineInterface cli_; + // Was DisallowPlugins() called? + bool disallow_plugins_; + // We create a directory within TestTempDir() in order to add extra // protection against accidentally deleting user files (since we recursively // delete this directory during the test). This is the full path of that @@ -166,40 +172,6 @@ class CommandLineInterfaceTest : public testing::Test { vector mock_generators_to_delete_; }; -// A mock CodeGenerator which outputs information about the context in which -// it was called, which can then be checked. Output is written to a filename -// constructed by concatenating the filename_prefix (given to the constructor) -// with the proto file name, separated by a '.'. -class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator { - public: - // Create a MockCodeGenerator whose Generate() method returns true. - MockCodeGenerator(const string& name, const string& filename_prefix); - - // Create a MockCodeGenerator whose Generate() method returns false - // and sets the error string to the given string. - MockCodeGenerator(const string& name, const string& filename_prefix, - const string& error); - - ~MockCodeGenerator(); - - void set_expect_write_error(bool value) { - expect_write_error_ = value; - } - - // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const; - - private: - string name_; - string filename_prefix_; - bool return_error_; - string error_; - bool expect_write_error_; -}; - class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { public: NullCodeGenerator() : called_(false) {} @@ -237,6 +209,22 @@ void CommandLineInterfaceTest::SetUp() { // Create the temp directory. GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE)); + + // Register generators. + CodeGenerator* generator = new MockCodeGenerator("test_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--test_out", generator, "Test output."); + cli_.RegisterGenerator("-t", generator, "Test output."); + + generator = new MockCodeGenerator("alt_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--alt_out", generator, "Alt output."); + + generator = new NullCodeGenerator(); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--null_out", generator, "Null output."); + + disallow_plugins_ = false; } void CommandLineInterfaceTest::TearDown() { @@ -254,6 +242,11 @@ void CommandLineInterfaceTest::Run(const string& command) { vector args; SplitStringUsing(command, " ", &args); + if (!disallow_plugins_) { + cli_.AllowPlugins("prefix-"); + args.push_back("--plugin=prefix-gen-plug=test_plugin"); + } + scoped_array argv(new const char*[args.size()]); for (int i = 0; i < args.size(); i++) { @@ -270,44 +263,6 @@ void CommandLineInterfaceTest::Run(const string& command) { // ------------------------------------------------------------------- -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterGenerator( - const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterErrorGenerator( - const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename_prefix, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename_prefix, error_text); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::NullCodeGenerator* -CommandLineInterfaceTest::RegisterNullGenerator( - const string& flag_name) { - NullCodeGenerator* generator = new NullCodeGenerator; - mock_generators_to_delete_.push_back(generator); - cli_.RegisterGenerator(flag_name, generator, ""); - return generator; -} - void CommandLineInterfaceTest::CreateTempFile( const string& name, const string& contents) { @@ -323,6 +278,10 @@ void CommandLineInterfaceTest::CreateTempFile( File::WriteStringToFileOrDie(contents, full_name); } +void CommandLineInterfaceTest::CreateTempDir(const string& name) { + File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777); +} + // ------------------------------------------------------------------- void CommandLineInterfaceTest::ExpectNoErrors() { @@ -348,25 +307,35 @@ bool CommandLineInterfaceTest::HasAlternateErrorSubstring( return error_text_.find(expected_substring) != string::npos; } +void CommandLineInterfaceTest::ExpectGenerated( + const string& generator_name, + const string& parameter, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, temp_directory_); +} + void CommandLineInterfaceTest::ExpectGenerated( const string& generator_name, const string& parameter, const string& proto_name, const string& message_name, - const string& output_file_prefix) { - // Open and read the file. - string output_file = output_file_prefix + "." + proto_name; - string file_contents; - ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file, - &file_contents)) - << "Failed to open file: " + output_file; + const string& output_directory) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, + temp_directory_ + "/" + output_directory); +} - // Check that the contents are as we expect. - string expected_contents = - generator_name + ": " + parameter + ", " + proto_name + ", " + - message_name + "\n"; - EXPECT_EQ(expected_contents, file_contents) - << "Output file did not have expected contents: " + output_file; +void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( + const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, insertions, proto_name, message_name, + temp_directory_); } void CommandLineInterfaceTest::ReadDescriptorSet( @@ -383,77 +352,52 @@ void CommandLineInterfaceTest::ReadDescriptorSet( // =================================================================== -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(false), - expect_write_error_(false) { -} - -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix, const string& error) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(true), - error_(error), - expect_write_error_(false) { -} +TEST_F(CommandLineInterfaceTest, BasicOutput) { + // Test that the common case works. -CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {} + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); -bool CommandLineInterfaceTest::MockCodeGenerator::Generate( - const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const { - scoped_ptr output( - output_directory->Open(filename_prefix_ + "." + file->name())); - io::Printer printer(output.get(), '$'); - map vars; - vars["name"] = name_; - vars["parameter"] = parameter; - vars["proto_name"] = file->name(); - vars["message_name"] = file->message_type_count() > 0 ? - file->message_type(0)->full_name().c_str() : "(none)"; - - printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n"); - - if (expect_write_error_) { - EXPECT_TRUE(printer.failed()); - } else { - EXPECT_FALSE(printer.failed()); - } + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); - *error = error_; - return !return_error_; + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } -// =================================================================== +TEST_F(CommandLineInterfaceTest, BasicPlugin) { + // Test that basic plugins work. -TEST_F(CommandLineInterfaceTest, BasicOutput) { - // Test that the common case works. + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { + // Invoke a generator and a plugin at the same time. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleInputs) { // Test parsing multiple input files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -461,48 +405,68 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs) { "syntax = \"proto2\";\n" "message Bar {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto bar.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); - ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_generator", "", "bar.proto", "Bar"); } TEST_F(CommandLineInterfaceTest, CreateDirectory) { // Test that when we output to a sub-directory, it is created. - RegisterGenerator("test_generator", "--test_out", - "bar/baz/output.test", "Test output."); - - CreateTempFile("foo.proto", + CreateTempFile("bar/baz/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + CreateTempDir("out"); + CreateTempDir("plugout"); - Run("protocol_compiler --test_out=$tmpdir " - "--proto_path=$tmpdir foo.proto"); + Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " + "--proto_path=$tmpdir bar/baz/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", - "foo.proto", "Foo", "bar/baz/output.test"); + ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); + ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); } TEST_F(CommandLineInterfaceTest, GeneratorParameters) { // Test that generator parameters are correctly parsed from the command line. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); Run("protocol_compiler --test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, Insert) { + // Test running a generator that inserts code into another's output. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert=test_generator,test_plugin:$tmpdir " + "--plug_out=insert=test_generator,test_plugin:$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "TestParameter", - "foo.proto", "Foo", "output.test"); + ExpectGeneratedWithInsertions( + "test_generator", "TestParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); + ExpectGeneratedWithInsertions( + "test_plugin", "TestPluginParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); } #if defined(_WIN32) || defined(__CYGWIN__) @@ -510,12 +474,10 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) { TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { // Test that the output path can be a Windows-style path. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=C:\\ " + Run("protocol_compiler --null_out=C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -526,12 +488,10 @@ TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { // Test that we can have a windows-style output path and a parameter. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=bar:C:\\ " + Run("protocol_compiler --null_out=bar:C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -543,9 +503,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { // Test that the directories can end in backslashes. Some users claim this // doesn't work on their system. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -554,7 +511,7 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { "--proto_path=$tmpdir\\ foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } #endif // defined(_WIN32) || defined(__CYGWIN__) @@ -562,9 +519,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { TEST_F(CommandLineInterfaceTest, PathLookup) { // Test that specifying multiple directories in the proto search path works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -580,15 +534,12 @@ TEST_F(CommandLineInterfaceTest, PathLookup) { "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { // Same as PathLookup, but we provide the proto_path in a single flag. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -613,15 +564,12 @@ TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { #undef PATH_SEPARATOR ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, NonRootMapping) { // Test setting up a search path mapping a directory to a non-root location. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -630,42 +578,34 @@ TEST_F(CommandLineInterfaceTest, NonRootMapping) { "--proto_path=bar=$tmpdir bar/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleGenerators) { // Test that we can have multiple generators and use both in one invocation, // each with a different output directory. - RegisterGenerator("test_generator_1", "--test1_out", - "output1.test", "Test output 1."); - RegisterGenerator("test_generator_2", "--test2_out", - "output2.test", "Test output 2."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); // Create the "a" and "b" sub-directories. - CreateTempFile("a/dummy", ""); - CreateTempFile("b/dummy", ""); + CreateTempDir("a"); + CreateTempDir("b"); Run("protocol_compiler " - "--test1_out=$tmpdir/a " - "--test2_out=$tmpdir/b " + "--test_out=$tmpdir/a " + "--alt_out=$tmpdir/b " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test"); - ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); + ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); } TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { // Test that --disallow_services doesn't cause a problem when there are no // services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -674,15 +614,12 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { // Test that --disallow_services produces an error when there are services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -697,9 +634,6 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { // Test that services work fine as long as --disallow_services is not used. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -709,7 +643,7 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { @@ -717,9 +651,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -728,7 +659,7 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { "--proto_path=$tmpdir $tmpdir/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { @@ -787,9 +718,6 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { TEST_F(CommandLineInterfaceTest, ParseErrors) { // Test that parse errors are reported. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -804,9 +732,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrors) { TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { // Test that parse errors are reported from multiple files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // We set up files such that foo.proto actually depends on bar.proto in // two ways: Directly and through baz.proto. bar.proto's errors should // only be reported once. @@ -834,9 +759,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { TEST_F(CommandLineInterfaceTest, InputNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); @@ -850,9 +772,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir $tmpdir/foo.proto"); @@ -866,9 +785,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -895,9 +811,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // Create a directory called "bar" so that we can point --proto_path at it. CreateTempFile("bar/dummy", ""); @@ -914,9 +827,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -938,9 +848,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir/foo foo.proto"); @@ -952,9 +859,6 @@ TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { TEST_F(CommandLineInterfaceTest, MissingInputError) { // Test that we get an error if no inputs are given. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir"); @@ -962,9 +866,6 @@ TEST_F(CommandLineInterfaceTest, MissingInputError) { } TEST_F(CommandLineInterfaceTest, MissingOutputError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -975,35 +876,56 @@ TEST_F(CommandLineInterfaceTest, MissingOutputError) { } TEST_F(CommandLineInterfaceTest, OutputWriteError) { - MockCodeGenerator* generator = - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - generator->set_expect_write_error(true); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + string output_file = + MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); + // Create a directory blocking our output location. - CreateTempFile("output.test.foo.proto/foo", ""); + CreateTempDir(output_file); Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); + ExpectErrorSubstring("MockCodeGenerator detected write error."); + #if defined(_WIN32) && !defined(__CYGWIN__) // Windows with MSVCRT.dll produces EPERM instead of EISDIR. - if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) { + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { return; } #endif - ExpectErrorSubstring("output.test.foo.proto: Is a directory"); + ExpectErrorSubstring(output_file + ": Is a directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + string output_file = + MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); + + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} +TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1011,14 +933,21 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { Run("protocol_compiler --test_out=$tmpdir/nosuchdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("nosuchdir/: " - "No such file or directory"); + ExpectErrorSubstring("nosuchdir/: No such file or directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1037,45 +966,109 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { } TEST_F(CommandLineInterfaceTest, GeneratorError) { - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { + // Test a generator plugin that returns an error. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" - "message Foo {}\n"); + "message MockCodeGenerator_Error {}\n"); - Run("protocol_compiler --error_out=$tmpdir " + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("--error_out: Test error message."); + ExpectErrorSubstring( + "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); } -TEST_F(CommandLineInterfaceTest, HelpText) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); +TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { + // Test a generator plugin that exits with an error code. CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Exit {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { + // Test a generator plugin that crashes. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Abort {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); + + // Don't depend on the exact signal number. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin killed by signal"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { + // Test what happens if the plugin isn't found. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " + "--plugin=prefix-gen-badplug=no_such_file " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring( + "no_such_file: program not found or is not executable"); + + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { + // Test what happens if plugins aren't allowed. + + CreateTempFile("error.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + DisallowPlugins(); + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring("Unknown flag: --plug_out"); +} + +TEST_F(CommandLineInterfaceTest, HelpText) { Run("test_exec_name --help"); ExpectErrorSubstring("Usage: test_exec_name "); ExpectErrorSubstring("--test_out=OUT_DIR"); ExpectErrorSubstring("Test output."); - ExpectErrorSubstring("--error_out=OUT_DIR"); - ExpectErrorSubstring("Test error output."); + ExpectErrorSubstring("--alt_out=OUT_DIR"); + ExpectErrorSubstring("Alt output."); } TEST_F(CommandLineInterfaceTest, GccFormatErrors) { // Test --error_format=gcc (which is the default, but we want to verify // that it can be set explicitly). - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1090,9 +1083,6 @@ TEST_F(CommandLineInterfaceTest, GccFormatErrors) { TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1108,9 +1098,6 @@ TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1128,9 +1115,6 @@ TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { // Test that a single-character flag works. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1139,15 +1123,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { // Test that separating the flag value with a space works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1156,16 +1137,13 @@ TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { // Test that separating the flag value with a space works for // single-character flags. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1174,15 +1152,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MissingValueError) { // Test that we get an error if a flag is missing its value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); ExpectErrorText("Missing value for flag: --test_out\n"); @@ -1192,9 +1167,6 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { // Test that we get an error if the last argument is a flag requiring a // value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out"); ExpectErrorText("Missing value for flag: --test_out\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index a7bc35bd..30b1d2bf 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -123,8 +123,11 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { Importer importer(&source_tree, &error_collector); const FileDescriptor* proto_file = importer.Import("google/protobuf/descriptor.proto"); + const FileDescriptor* plugin_proto_file = + importer.Import("google/protobuf/compiler/plugin.proto"); EXPECT_EQ("", error_collector.text_); ASSERT_TRUE(proto_file != NULL); + ASSERT_TRUE(plugin_proto_file != NULL); CppGenerator generator; MockOutputDirectory output_directory; @@ -133,11 +136,18 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &output_directory, &error)); + parameter = "dllexport_decl=LIBPROTOC_EXPORT"; + ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, + &output_directory, &error)); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h", "google/protobuf/descriptor.pb.h"); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc", "google/protobuf/descriptor.pb.cc"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h", + "google/protobuf/compiler/plugin.pb.h"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", + "google/protobuf/compiler/plugin.pb.cc"); } } // namespace @@ -145,5 +155,4 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 90e9172a..76d2b798 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -98,6 +98,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "$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" + "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n" "\n"); if (HasDescriptorMethods(descriptor_->file())) { @@ -149,17 +150,21 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { "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"); + " $classname$_$nested_name$_MAX;\n" + "static const int $nested_name$_ARRAYSIZE =\n" + " $classname$_$nested_name$_ARRAYSIZE;\n"); if (HasDescriptorMethods(descriptor_->file())) { printer->Print(vars, "static inline const ::google::protobuf::EnumDescriptor*\n" "$nested_name$_descriptor() {\n" " return $classname$_descriptor();\n" - "}\n" + "}\n"); + printer->Print(vars, "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" " return $classname$_Name(value);\n" - "}\n" + "}\n"); + printer->Print(vars, "static inline bool $nested_name$_Parse(const ::std::string& name,\n" " $nested_name$* value) {\n" " return $classname$_Parse(name, value);\n" @@ -240,7 +245,8 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { } printer->Print(vars, "const $classname$ $parent$::$nested_name$_MIN;\n" - "const $classname$ $parent$::$nested_name$_MAX;\n"); + "const $classname$ $parent$::$nested_name$_MAX;\n" + "const int $parent$::$nested_name$_ARRAYSIZE;\n"); printer->Print("#endif // _MSC_VER\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 7ca11c8c..91ce493a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -114,7 +114,9 @@ void EnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" "if ($type$_IsValid(value)) {\n" " set_$name$(static_cast< $type$ >(value));\n"); if (HasUnknownFields(descriptor_->file())) { @@ -170,24 +172,17 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedField* 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"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField* mutable_$name$()$deprecation$;\n"); } void RepeatedEnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline $type$ $classname$::$name$(int index) const {\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" @@ -199,6 +194,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GOOGLE_DCHECK($type$_IsValid(value));\n" " $name$_.Add(value);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedEnumFieldGenerator:: @@ -223,7 +227,33 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { + // Don't use ReadRepeatedPrimitive here so that the enum can be validated. + printer->Print(variables_, + "int value;\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" + "if ($type$_IsValid(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("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + if (!descriptor_->options().packed()) { + // We use a non-inlined implementation in this case, since this path will + // rarely be executed. + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" + " input,\n" + " &$type$_IsValid,\n" + " this->mutable_$name$())));\n"); + } else { printer->Print(variables_, "::google::protobuf::uint32 length;\n" "DO_(input->ReadVarint32(&length));\n" @@ -231,25 +261,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "input->PushLimit(length);\n" "while (input->BytesUntilLimit() > 0) {\n" " int value;\n" - " DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n" + " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" " if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" " }\n" "}\n" "input->PopLimit(limit);\n"); - } else { - printer->Print(variables_, - "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n" - "if ($type$_IsValid(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"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 20dd57bb..0793430c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -83,6 +83,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 7208ed3a..658a7077 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include #include #include #include @@ -43,6 +44,18 @@ namespace protobuf { namespace compiler { namespace cpp { +namespace { + +// Returns the fully-qualified class name of the message that this field +// extends. This function is used in the Google-internal code to handle some +// legacy cases. +string ExtendeeClassName(const FieldDescriptor* descriptor) { + const Descriptor* extendee = descriptor->containing_type(); + return ClassName(extendee, true); +} + +} // anonymous namespace + ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, const string& dllexport_decl) : descriptor_(descriptor), @@ -80,7 +93,7 @@ ExtensionGenerator::~ExtensionGenerator() {} void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; vars["name" ] = descriptor_->name(); @@ -106,6 +119,7 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" " $name$;\n" ); + } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { @@ -115,7 +129,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { string name = scope + descriptor_->name(); map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["type_traits" ] = type_traits_; vars["name" ] = name; vars["constant_name"] = FieldConstantName(descriptor_); @@ -154,7 +168,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; @@ -193,5 +207,4 @@ void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index c546e964..103cac4a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -61,11 +62,24 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); (*variables)["deprecation"] = descriptor->options().deprecated() - ? " DEPRECATED_PROTOBUF_FIELD" : ""; + ? " PROTOBUF_DEPRECATED" : ""; + } FieldGenerator::~FieldGenerator() {} +void FieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() " + << "called on field generator that does not support packing."; + +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) : descriptor_(descriptor), field_generators_( @@ -82,7 +96,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new RepeatedMessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field); + switch (field->options().ctype()) { + default: // RepeatedStringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new RepeatedStringFieldGenerator(field); + } case FieldDescriptor::CPPTYPE_ENUM: return new RepeatedEnumFieldGenerator(field); default: @@ -93,7 +111,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new MessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field); + switch (field->options().ctype()) { + default: // StringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new StringFieldGenerator(field); + } case FieldDescriptor::CPPTYPE_ENUM: return new EnumFieldGenerator(field); default: @@ -110,6 +132,7 @@ const FieldGenerator& FieldGeneratorMap::get( return *field_generators_[field->index()]; } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 00ec2c7c..c303a337 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -118,6 +118,11 @@ class FieldGenerator { // message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; + // Generate lines to decode this field from a packed value, which will be + // placed inside the message's MergeFromCodedStream() method. + virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) + const; + // Generate lines to serialize this field, which are placed within the // message's SerializeWithCachedSizes() method. virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; @@ -153,6 +158,7 @@ class FieldGeneratorMap { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 51859bb3..80da7e40 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -93,12 +94,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" "\n" "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" "#define PROTOBUF_$filename_identifier$__INCLUDED\n" "\n" "#include \n" "\n", + "filename", file_->name(), "filename_identifier", filename_identifier); printer->Print( @@ -132,19 +135,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { if (HasDescriptorMethods(file_)) { printer->Print( "#include \n"); + } - if (file_->service_count() > 0) { - printer->Print( - "#include \n"); - } + if (HasGenericServices(file_)) { + printer->Print( + "#include \n"); } + for (int i = 0; i < file_->dependency_count(); i++) { printer->Print( "#include \"$dependency$.pb.h\"\n", "dependency", StripProto(file_->dependency(i)->name())); } + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + // Open namespace. GenerateNamespaceOpeners(printer); @@ -198,7 +205,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print(kThickSeparator); printer->Print("\n"); - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate service definitions. for (int i = 0; i < file_->service_count(); i++) { if (i > 0) { @@ -232,6 +239,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { message_generators_[i]->GenerateInlineMethods(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -255,10 +266,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "\n" "} // namespace google\n} // namespace protobuf\n" - "#endif // SWIG\n" - "\n"); + "#endif // SWIG\n"); } + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + printer->Print( "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", "filename_identifier", filename_identifier); @@ -285,6 +300,9 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include \n"); } + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + GenerateNamespaceOpeners(printer); if (HasDescriptorMethods(file_)) { @@ -300,10 +318,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "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()); + + if (HasGenericServices(file_)) { + 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( @@ -329,7 +350,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { message_generators_[i]->GenerateClassMethods(printer); } - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate services. for (int i = 0; i < file_->service_count(); i++) { if (i == 0) printer->Print("\n"); @@ -344,7 +365,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) { extension_generators_[i]->GenerateDefinition(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateNamespaceClosers(printer); + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); } void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { @@ -397,8 +426,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { 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); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + service_generators_[i]->GenerateDescriptorInitializer(printer, i); + } } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 723a8b45..e3df88b0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include @@ -40,6 +41,7 @@ #include #include + namespace google { namespace protobuf { namespace compiler { @@ -111,6 +113,7 @@ const char kThinSeparator[] = "// -------------------------------------------------------------------\n"; string ClassName(const Descriptor* descriptor, bool qualified) { + // Find "outer", the descriptor of the top-level message in which // "descriptor" is embedded. const Descriptor* outer = descriptor; @@ -141,6 +144,12 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } } + +string SuperClassName(const Descriptor* descriptor) { + return HasDescriptorMethods(descriptor->file()) ? + "::google::protobuf::Message" : "::google::protobuf::MessageLite"; +} + string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -166,6 +175,12 @@ string FieldConstantName(const FieldDescriptor *field) { return result; } +string FieldMessageTypeName(const FieldDescriptor* field) { + // Note: The Google-internal version of Protocol Buffers uses this function + // as a hook point for hacks to support legacy code. + return ClassName(field->message_type(), true); +} + string StripProto(const string& filename) { if (HasSuffixString(filename, ".protodevel")) { return StripSuffixString(filename, ".protodevel"); @@ -235,17 +250,37 @@ string DefaultValue(const FieldDescriptor* field) { return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; case FieldDescriptor::CPPTYPE_UINT64: return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits::infinity()) { + return "::google::protobuf::internal::Infinity()"; + } else if (value == -numeric_limits::infinity()) { + return "-::google::protobuf::internal::Infinity()"; + } else if (value != value) { + return "::google::protobuf::internal::NaN()"; + } else { + return SimpleDtoa(value); + } + } case FieldDescriptor::CPPTYPE_FLOAT: { - // If floating point value contains a period (.) or an exponent (either - // E or e), then append suffix 'f' to make it a floating-point literal. - string float_value = SimpleFtoa(field->default_value_float()); - if (float_value.find_first_of(".eE") != string::npos) { - float_value.push_back('f'); + float value = field->default_value_float(); + if (value == numeric_limits::infinity()) { + return "static_cast(::google::protobuf::internal::Infinity())"; + } else if (value == -numeric_limits::infinity()) { + return "static_cast(-::google::protobuf::internal::Infinity())"; + } else if (value != value) { + return "static_cast(::google::protobuf::internal::NaN())"; + } else { + string float_value = SimpleFtoa(value); + // If floating point value contains a period (.) or an exponent + // (either E or e), then append suffix 'f' to make it a float + // literal. + if (float_value.find_first_of(".eE") != string::npos) { + float_value.push_back('f'); + } + return float_value; } - return float_value; } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; @@ -259,7 +294,7 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_STRING: return "\"" + CEscape(field->default_value_string()) + "\""; case FieldDescriptor::CPPTYPE_MESSAGE: - return ClassName(field->message_type(), true) + "::default_instance()"; + return FieldMessageTypeName(field) + "::default_instance()"; } // Can't actually get here; make compiler happy. (We could add a default // case above but then we wouldn't get the nice compiler warning when a diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 83e12501..f99b5fe8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -60,6 +60,8 @@ extern const char kThinSeparator[]; string ClassName(const Descriptor* descriptor, bool qualified); string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +string SuperClassName(const Descriptor* descriptor); + // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names @@ -77,6 +79,10 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { field->extension_scope() : field->containing_type(); } +// Returns the fully-qualified type name field->message_type(). Usually this +// is just ClassName(field->message_type(), true); +string FieldMessageTypeName(const FieldDescriptor* field); + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); @@ -107,33 +113,41 @@ string GlobalAssignDescriptorsName(const string& filename); string GlobalShutdownFileName(const string& filename); // Do message classes in this file keep track of unknown fields? -inline const bool HasUnknownFields(const FileDescriptor *file) { +inline 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) { +inline 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) { +inline bool HasDescriptorMethods(const FileDescriptor *file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().optimize_for() != FileOptions::LITE_RUNTIME && + file->options().cc_generic_services(); +} + // Should string fields in this file verify that their contents are UTF-8? -inline const bool HasUtf8Verification(const FileDescriptor* file) { +inline bool HasUtf8Verification(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } // Should we generate a separate, super-optimized code path for serializing to // flat arrays? We don't do this in Lite mode because we'd rather reduce code // size. -inline const bool HasFastArraySerialization(const FileDescriptor* file) { +inline bool HasFastArraySerialization(const FileDescriptor* file) { return file->options().optimize_for() == FileOptions::SPEED; } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index eb836418..cbdcce8f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -308,11 +308,10 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = dllexport_decl_ + " "; } - vars["superclass"] = HasDescriptorMethods(descriptor_->file()) ? - "Message" : "MessageLite"; + vars["superclass"] = SuperClassName(descriptor_); printer->Print(vars, - "class $dllexport$$classname$ : public ::google::protobuf::$superclass$ {\n" + "class $dllexport$$classname$ : public $superclass$ {\n" " public:\n"); printer->Indent(); @@ -349,6 +348,10 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(vars, "static const $classname$& default_instance();\n" + "\n"); + + + printer->Print(vars, "void Swap($classname$* other);\n" "\n" "// implements Message ----------------------------------------------\n" @@ -387,7 +390,7 @@ GenerateClassDefinition(io::Printer* printer) { "private:\n" "void SharedCtor();\n" "void SharedDtor();\n" - "void SetCachedSize(int size) const { _cached_size_ = size; }\n" + "void SetCachedSize(int size) const;\n" "public:\n" "\n"); @@ -436,6 +439,11 @@ GenerateClassDefinition(io::Printer* printer) { extension_generators_[i]->GenerateDeclaration(printer); } + + printer->Print( + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + // Generate private members for fields. printer->Outdent(); printer->Print(" private:\n"); @@ -623,6 +631,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); } + } void MessageGenerator:: @@ -751,6 +760,7 @@ GenerateClassMethods(io::Printer* printer) { "classname", classname_, "type_name", descriptor_->full_name()); } + } void MessageGenerator:: @@ -833,9 +843,8 @@ GenerateSharedDestructorCode(io::Printer* printer) { void MessageGenerator:: GenerateStructors(io::Printer* printer) { - string superclass = HasDescriptorMethods(descriptor_->file()) ? - "Message" : "MessageLite"; - + string superclass = SuperClassName(descriptor_); + // Generate the default constructor. printer->Print( "$classname$::$classname$()\n" @@ -864,7 +873,7 @@ GenerateStructors(io::Printer* printer) { printer->Print( " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", "name", FieldName(field), - "type", ClassName(field->message_type(), true)); + "type", FieldMessageTypeName(field)); } } printer->Print( @@ -896,6 +905,15 @@ GenerateStructors(io::Printer* printer) { // Generate the shared destructor code. GenerateSharedDestructorCode(printer); + // Generate SetCachedSize. + printer->Print( + "void $classname$::SetCachedSize(int size) const {\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + " _cached_size_ = size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + "}\n", + "classname", classname_); + // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file()) && !descriptor_->options().no_standard_descriptor_accessor()) { @@ -924,6 +942,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "adddescriptorsname", GlobalAddDescriptorsName(descriptor_->file()->name())); + } void MessageGenerator:: @@ -1237,12 +1256,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { PrintFieldComment(printer, field); printer->Print( - "case $number$: {\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()), + "case $number$: {\n", + "number", SimpleItoa(field->number())); + printer->Indent(); + const FieldGenerator& field_generator = field_generators_.get(field); + + // Emit code to parse the common, expected case. + printer->Print( + "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n", "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]); if (i > 0 || (field->is_repeated() && !field->options().packed())) { @@ -1252,8 +1274,38 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Indent(); + if (field->options().packed()) { + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + } else { + field_generator.GenerateMergeFromCodedStream(printer); + } + printer->Outdent(); - field_generators_.get(field).GenerateMergeFromCodedStream(printer); + // Emit code to parse unexpectedly packed or unpacked values. + if (field->is_packable() && field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_$wiretype$) {\n", + "wiretype", + kWireTypeNames[WireFormat::WireTypeForFieldType(field->type())]); + printer->Indent(); + field_generator.GenerateMergeFromCodedStream(printer); + printer->Outdent(); + } else if (field->is_packable() && !field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_LENGTH_DELIMITED) {\n"); + printer->Indent(); + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + printer->Outdent(); + } + + printer->Print( + "} else {\n" + " goto handle_uninterpreted;\n" + "}\n"); // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. @@ -1434,18 +1486,6 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { "classname", classname_); printer->Indent(); - 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(); @@ -1555,7 +1595,9 @@ GenerateByteSize(io::Printer* printer) { " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"); } printer->Print( + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" " _cached_size_ = total_size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" " return total_size;\n" "}\n"); return; @@ -1647,7 +1689,9 @@ GenerateByteSize(io::Printer* printer) { // exact same value, it works on all common processors. In a future version // of C++, _cached_size_ should be made into an atomic. printer->Print( + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" "_cached_size_ = total_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "return total_size;\n"); printer->Outdent(); @@ -1719,6 +1763,7 @@ GenerateIsInitialized(io::Printer* printer) { "}\n"); } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index f1c57141..04778f6d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -150,6 +150,7 @@ class MessageGenerator { io::Printer* printer, const Descriptor::ExtensionRange* range, bool unbounded); + const Descriptor* descriptor_; string classname_; string dllexport_decl_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 059fba6e..c04bdc66 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -47,7 +47,11 @@ namespace { void SetMessageVariables(const FieldDescriptor* descriptor, map* variables) { SetCommonFieldVariables(descriptor, variables); - (*variables)["type"] = ClassName(descriptor->message_type(), true); + (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["stream_writer"] = (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file()) ? + "MaybeToArray" : + ""); } } // namespace @@ -125,7 +129,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n" + "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(), output);\n"); } @@ -164,26 +168,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "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"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline const $type$& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -193,6 +190,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline $type$* $classname$::add_$name$() {\n" " return $name$_.Add();\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedMessageFieldGenerator:: @@ -232,7 +238,7 @@ void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n" + " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(i), output);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 81f5ce07..a69c48b5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -84,10 +84,14 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, SetCommonFieldVariables(descriptor, variables); (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); (*variables)["default"] = DefaultValue(descriptor); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); int fixed_size = FixedSize(descriptor->type()); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } + (*variables)["wire_format_field_type"] = + "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( + static_cast(descriptor->type())); } } // namespace @@ -149,8 +153,9 @@ GenerateConstructorCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &$name$_));\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, $wire_format_field_type$>(\n" + " input, &$name$_)));\n" "_set_bit($index$);\n"); } @@ -188,6 +193,14 @@ RepeatedPrimitiveFieldGenerator:: RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor) : descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_); + + if (descriptor->options().packed()) { + variables_["packed_reader"] = "ReadPackedPrimitive"; + variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; + } else { + variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; + variables_["repeated_reader"] = "ReadRepeatedPrimitive"; + } } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} @@ -205,25 +218,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "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"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline $type$ $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -233,6 +240,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline void $classname$::add_$name$($type$ value) {\n" " $name$_.Add(value);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -257,30 +273,18 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print("{\n"); - printer->Indent(); - printer->Print(variables_, - "::google::protobuf::uint32 length;\n" - "DO_(input->ReadVarint32(&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::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - " add_$name$(value);\n" - "}\n" - "input->PopLimit(limit);\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print(variables_, - "$type$ value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - "add_$name$(value);\n"); - } + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " $tag_size$, $tag$, input, this->mutable_$name$())));\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " input, this->mutable_$name$())));\n"); } void RepeatedPrimitiveFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 6b96614c..8fcd74ae 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -83,6 +83,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 72258e89..ea6809a9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -91,7 +91,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { // files that applied the ctype. The field can still be accessed via the // reflection interface since the reflection interface is independent of // the string's underlying representation. - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -107,7 +107,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$deprecation$;\n" "inline ::std::string* mutable_$name$()$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -278,7 +278,7 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { // See comment above about unknown ctypes. - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -287,10 +287,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "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" @@ -304,7 +300,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline void add_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" + "$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + "$deprecation$;\n"); + + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -314,14 +316,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline const ::std::string& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -353,6 +347,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" " $name$_.Add()->assign(reinterpret_cast(value), size);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedStringFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index d7575c05..a7e852de 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -154,6 +155,16 @@ TEST(GeneratedMessageTest, FloatingPointDefaults) { EXPECT_EQ(-1.5f, extreme_default.negative_float()); EXPECT_EQ(2.0e8f, extreme_default.large_float()); EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); } TEST(GeneratedMessageTest, Accessors) { @@ -779,22 +790,39 @@ TEST(GeneratedEnumTest, IsValidValue) { } TEST(GeneratedEnumTest, MinAndMax) { - EXPECT_EQ(unittest::TestAllTypes::FOO,unittest::TestAllTypes::NestedEnum_MIN); - EXPECT_EQ(unittest::TestAllTypes::BAZ,unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(unittest::TestAllTypes::FOO, + unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(unittest::TestAllTypes::BAZ, + unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, unittest::TestAllTypes::NestedEnum_ARRAYSIZE); EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN); EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX); + EXPECT_EQ(7, unittest::ForeignEnum_ARRAYSIZE); EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN); EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, unittest::TestEnumWithDupValue_ARRAYSIZE); EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN); EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX); + EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE); - // Make sure we can use _MIN and _MAX as switch cases. - switch(unittest::SPARSE_A) { + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* nullptr = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(nullptr, &unittest::ForeignEnum_MIN); + EXPECT_NE(nullptr, &unittest::ForeignEnum_MAX); + EXPECT_NE(nullptr, &unittest::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases. + switch (unittest::SPARSE_A) { case unittest::TestSparseEnum_MIN: case unittest::TestSparseEnum_MAX: + case unittest::TestSparseEnum_ARRAYSIZE: break; default: break; @@ -1136,6 +1164,43 @@ TEST_F(GeneratedServiceTest, NotImplemented) { EXPECT_TRUE(controller.called_); } +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GeneratedServiceTest, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension(no_generic_services_test::test_extension, 123); + no_generic_services_test::TestEnum e = no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + no_generic_services_test::TestMessage::descriptor()->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS // =================================================================== diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 8ade50c9..85e39f53 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -223,6 +223,11 @@ void EnumGenerator::Generate(io::Printer* printer) { "file", ClassName(descriptor_->file())); } + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + printer->Outdent(); printer->Print("}\n\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index dc36e06e..af6b1cd2 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -62,7 +62,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); } } // namespace @@ -81,7 +81,7 @@ void EnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $default$;\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -110,6 +110,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void EnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + void EnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -240,6 +245,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedEnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -262,15 +272,6 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - // If packed, set up the while loop - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int oldLimit = input.pushLimit(length);\n" - "while(input.getBytesUntilLimit() > 0) {\n"); - printer->Indent(); - } - // Read and store the enum printer->Print(variables_, "int rawValue = input.readEnum();\n" @@ -287,13 +288,24 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, " add$capitalized_name$(value);\n" "}\n"); +} - if (descriptor_->options().packed()) { - printer->Outdent(); - printer->Print(variables_, - "}\n" - "input.popLimit(oldLimit);\n"); - } +void RepeatedEnumFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Wrap GenerateParsingCode's contents with a while loop. + + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + + GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); } void RepeatedEnumFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 63f68153..c54a0faf 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -52,6 +52,7 @@ class EnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 4403220b..5932433f 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -133,7 +133,7 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) { 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["type_constant"] = TypeName(GetType(descriptor_)); vars["packed"] = descriptor_->options().packed() ? "true" : "false"; vars["enum_map"] = "null"; vars["prototype"] = "null"; @@ -208,5 +208,4 @@ void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) { } // namespace java } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index f9d34ad7..978c8f33 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -46,6 +46,16 @@ namespace java { FieldGenerator::~FieldGenerator() {} +void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " + << "called on field generator that does not support packing."; +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) : descriptor_(descriptor), field_generators_( diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index cab463c8..f5bef7ab 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -57,9 +57,11 @@ class FieldGenerator { virtual void GenerateMembers(io::Printer* printer) const = 0; virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; virtual void GenerateMergingCode(io::Printer* printer) const = 0; virtual void GenerateBuildingCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; virtual void GenerateSerializationCode(io::Printer* printer) const = 0; virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 2aedde5e..7ea127c0 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -64,7 +64,7 @@ bool UsesExtensions(const Message& message) { for (int i = 0; i < fields.size(); i++) { if (fields[i]->is_extension()) return true; - if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { if (fields[i]->is_repeated()) { int size = reflection->FieldSize(message, fields[i]); for (int j = 0; j < size; j++) { @@ -82,6 +82,7 @@ bool UsesExtensions(const Message& message) { return false; } + } // namespace FileGenerator::FileGenerator(const FileDescriptor* file) @@ -134,7 +135,9 @@ void FileGenerator::Generate(io::Printer* printer) { // fully-qualified names in the generated source. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); + "// source: $filename$\n" + "\n", + "filename", file_->name()); if (!java_package_.empty()) { printer->Print( "package $package$;\n" @@ -178,8 +181,10 @@ void FileGenerator::Generate(io::Printer* printer) { for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator(file_->message_type(i)).Generate(printer); } - for (int i = 0; i < file_->service_count(); i++) { - ServiceGenerator(file_->service(i)).Generate(printer); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + ServiceGenerator(file_->service(i)).Generate(printer); + } } } @@ -228,6 +233,10 @@ void FileGenerator::Generate(io::Printer* printer) { "\n" "public static void internalForceInit() {}\n"); + printer->Print( + "\n" + "// @@protoc_insertion_point(outer_class_scope)\n"); + printer->Outdent(); printer->Print("}\n"); } @@ -245,6 +254,7 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { // embedded raw, which is what we want. FileDescriptorProto file_proto; file_->CopyTo(&file_proto); + string file_data; file_proto.SerializeToString(&file_data); @@ -343,9 +353,11 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < file_->dependency_count(); i++) { - printer->Print( - " $dependency$.getDescriptor(),\n", - "dependency", ClassName(file_->dependency(i))); + if (ShouldIncludeDependency(file_->dependency(i))) { + printer->Print( + " $dependency$.getDescriptor(),\n", + "dependency", ClassName(file_->dependency(i))); + } } printer->Print( @@ -396,14 +408,20 @@ void FileGenerator::GenerateSiblings(const string& package_dir, file_->message_type(i), output_directory, file_list); } - for (int i = 0; i < file_->service_count(); i++) { - GenerateSibling(package_dir, java_package_, - file_->service(i), - output_directory, file_list); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + GenerateSibling(package_dir, java_package_, + file_->service(i), + output_directory, file_list); + } } } } +bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { + return true; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index cb82cea2..9e35d330 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -77,6 +77,11 @@ class FileGenerator { const string& classname() { return classname_; } private: + // Returns whether the dependency should be included in the output file. + // Always returns true for opensource, but used internally at Google to help + // improve compatibility with version 1 of protocol buffers. + bool ShouldIncludeDependency(const FileDescriptor* descriptor); + const FileDescriptor* file_; string java_package_; string classname_; diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index 8ed3affb..745b55ae 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -45,6 +45,7 @@ namespace protobuf { namespace compiler { namespace java { + JavaGenerator::JavaGenerator() {} JavaGenerator::~JavaGenerator() {} diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index dc6748e3..7ed0c3cc 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include @@ -57,7 +58,7 @@ const string& FieldName(const FieldDescriptor* field) { // Groups are hacky: The name of the field is just the lower-cased name // of the group type. In Java, though, we would like to retain the original // capitalization of the type name. - if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(field) == FieldDescriptor::TYPE_GROUP) { return field->message_type()->name(); } else { return field->name(); @@ -178,8 +179,12 @@ string FieldConstantName(const FieldDescriptor *field) { return name; } -JavaType GetJavaType(FieldDescriptor::Type field_type) { - switch (field_type) { +FieldDescriptor::Type GetType(const FieldDescriptor* field) { + return field->type(); +} + +JavaType GetJavaType(const FieldDescriptor* field) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_SINT32: @@ -254,7 +259,7 @@ bool AllAscii(const string& text) { } string DefaultValue(const FieldDescriptor* field) { - // Switch on cpp_type since we need to know which default_value_* method + // Switch on CppType since we need to know which default_value_* method // of FieldDescriptor to call. switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -267,14 +272,34 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(static_cast(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_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits::infinity()) { + return "Double.POSITIVE_INFINITY"; + } else if (value == -numeric_limits::infinity()) { + return "Double.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Double.NaN"; + } else { + return SimpleDtoa(value) + "D"; + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field->default_value_float(); + if (value == numeric_limits::infinity()) { + return "Float.POSITIVE_INFINITY"; + } else if (value == -numeric_limits::infinity()) { + return "Float.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Float.NaN"; + } else { + return SimpleFtoa(value) + "F"; + } + } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { + if (GetType(field) == FieldDescriptor::TYPE_BYTES) { if (field->has_default_value()) { // See comments in Internal.java for gory details. return strings::Substitute( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index f1b643c3..3c8974c9 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -93,6 +93,11 @@ string ClassName(const FileDescriptor* descriptor); // number constant. string FieldConstantName(const FieldDescriptor *field); +// Returns the type of the FieldDescriptor. +// This does nothing interesting for the open source release, but is used for +// hacks that improve compatability with version 1 protocol buffers at Google. +FieldDescriptor::Type GetType(const FieldDescriptor* field); + enum JavaType { JAVATYPE_INT, JAVATYPE_LONG, @@ -105,11 +110,7 @@ enum JavaType { JAVATYPE_MESSAGE }; -JavaType GetJavaType(FieldDescriptor::Type field_type); - -inline JavaType GetJavaType(const FieldDescriptor* field) { - return GetJavaType(field->type()); -} +JavaType GetJavaType(const FieldDescriptor* field); // Get the fully-qualified class name for a boxed primitive type, e.g. // "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message @@ -145,6 +146,13 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { FileOptions::LITE_RUNTIME; } +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().optimize_for() != FileOptions::LITE_RUNTIME && + file->options().java_generic_services(); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 99b57c95..1f8e209c 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -127,7 +127,7 @@ static bool HasRequiredFields( if (field->is_required()) { return true; } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { if (HasRequiredFields(field->message_type(), already_seen)) { return true; } @@ -292,9 +292,14 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Indent(); printer->Print( "// Use $classname$.newBuilder() to construct.\n" - "private $classname$() {}\n" + "private $classname$() {\n" + " initFields();\n" + "}\n" + // Used when constructing the default instance, which cannot be initialized + // immediately because it may cyclically refer to other default instances. + "private $classname$(boolean noInit) {}\n" "\n" - "private static final $classname$ defaultInstance = new $classname$();\n" + "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" " return defaultInstance;\n" "}\n" @@ -344,6 +349,17 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } + // Called by the constructor, except in the case of the default instance, + // in which case this is called by static init code later on. + printer->Print("private void initFields() {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + printer->Outdent(); + printer->Print("}\n"); + if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); @@ -352,25 +368,23 @@ void MessageGenerator::Generate(io::Printer* printer) { GenerateParseFromMethods(printer); GenerateBuilder(printer); - 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. + // not be initialized. Also carefully initialize the default instance in + // such a way that it doesn't conflict with other initialization. printer->Print( "\n" "static {\n" + " defaultInstance = new $classname$(true);\n" " $file$.internalForceInit();\n" + " defaultInstance.initFields();\n" "}\n", - "file", ClassName(descriptor_->file())); + "file", ClassName(descriptor_->file()), + "classname", descriptor_->name()); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); @@ -529,14 +543,23 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input).buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n" - " .buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" @@ -827,7 +850,7 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForField(field)); + WireFormat::WireTypeForFieldType(field->type())); printer->Print( "case $tag$: {\n", @@ -840,6 +863,24 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { printer->Print( " break;\n" "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(packed_tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } } printer->Outdent(); @@ -875,7 +916,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all embedded messages are initialized. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + if (GetJavaType(field) == JAVATYPE_MESSAGE && HasRequiredFields(field->message_type())) { switch (field->label()) { case FieldDescriptor::LABEL_REQUIRED: diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index bbddddde..71edc024 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -59,7 +59,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["type"] = ClassName(descriptor->message_type()); (*variables)["group_or_message"] = - (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; } @@ -79,7 +79,7 @@ void MessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $type$.getDefaultInstance();\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -124,6 +124,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void MessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); +} + void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -145,7 +150,7 @@ GenerateParsingCode(io::Printer* printer) const { " subBuilder.mergeFrom(get$capitalized_name$());\n" "}\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { @@ -261,6 +266,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedMessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -286,7 +296,7 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "$type$.Builder subBuilder = $type$.newBuilder();\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h index 90a90976..66bdd884 100644 --- a/src/google/protobuf/compiler/java/java_message_field.h +++ b/src/google/protobuf/compiler/java/java_message_field.h @@ -52,6 +52,7 @@ class MessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,6 +76,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 1fbca5a2..f6179bfa 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -93,7 +93,7 @@ bool IsReferenceType(JavaType type) { } const char* GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32 : return "Int32" ; case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; @@ -166,7 +166,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - WireFormat::TagSize(descriptor->number(), descriptor->type())); + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { (*variables)["null_check"] = " if (value == null) {\n" @@ -175,7 +175,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, } else { (*variables)["null_check"] = ""; } - int fixed_size = FixedSize(descriptor->type()); + int fixed_size = FixedSize(GetType(descriptor)); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } @@ -218,7 +218,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n" "public Builder clear$capitalized_name$() {\n" " result.has$capitalized_name$ = false;\n"); - if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { // The default value is not a simple literal so we want to avoid executing // it multiple times. Instead, get the default out of the default instance. printer->Print(variables_, @@ -232,6 +233,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void PrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void PrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -345,6 +351,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedPrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedPrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -367,18 +378,19 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" - "}\n" - "input.popLimit(limit);\n"); - } else { - printer->Print(variables_, - "add$capitalized_name$(input.read$capitalized_type$());\n"); - } + printer->Print(variables_, + "add$capitalized_name$(input.read$capitalized_type$());\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " add$capitalized_name$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -407,7 +419,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { " int dataSize = 0;\n"); printer->Indent(); - if (FixedSize(descriptor_->type()) == -1) { + if (FixedSize(GetType(descriptor_)) == -1) { printer->Print(variables_, "for ($type$ element : get$capitalized_name$List()) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h index f9da0a62..4e482a05 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.h +++ b/src/google/protobuf/compiler/java/java_primitive_field.h @@ -52,6 +52,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 0a2c0b2c..d9b0c3f9 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -39,6 +39,7 @@ int main(int argc, char* argv[]) { google::protobuf::compiler::CommandLineInterface cli; + cli.AllowPlugins("protoc-"); // Proto2 C++ google::protobuf::compiler::cpp::CppGenerator cpp_generator; diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 02304d6d..758f70dc 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -34,8 +34,9 @@ // // Recursive descent FTW. -#include #include +#include +#include #include @@ -206,6 +207,14 @@ bool Parser::ConsumeNumber(double* output, const char* error) { *output = value; input_->Next(); return true; + } else if (LookingAt("inf")) { + *output = numeric_limits::infinity(); + input_->Next(); + return true; + } else if (LookingAt("nan")) { + *output = numeric_limits::quiet_NaN(); + input_->Next(); + return true; } else { AddError(error); return false; diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index c4f08e7f..e2262b8b 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -336,6 +336,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " required double foo = 1 [default= 10.5];\n" " required double foo = 1 [default=-11.5];\n" " required double foo = 1 [default= 12 ];\n" + " required double foo = 1 [default= inf ];\n" + " required double foo = 1 [default=-inf ];\n" + " required double foo = 1 [default= nan ];\n" " required string foo = 1 [default='13\\001'];\n" " required string foo = 1 [default='a' \"b\" \n \"c\"];\n" " required bytes foo = 1 [default='14\\002'];\n" @@ -367,6 +370,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }" " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }" " field { type:TYPE_STRING default_value:\"abc\" "ETC" }" " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }" diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index d301f015..54ab0a2d 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -42,8 +42,9 @@ // performance-minded Python code leverage the fast C++ implementation // directly. -#include +#include #include +#include #include #include @@ -105,6 +106,13 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, const char kDescriptorKey[] = "DESCRIPTOR"; +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().py_generic_services(); +} + + // Prints the common boilerplate needed at the top of every .py // file output by this generator. void PrintTopBoilerplate( @@ -115,14 +123,21 @@ void PrintTopBoilerplate( "\n" "from google.protobuf import descriptor\n" "from google.protobuf import message\n" - "from google.protobuf import reflection\n" - "from google.protobuf import service\n" - "from google.protobuf import service_reflection\n"); + "from google.protobuf import reflection\n"); + if (HasGenericServices(file)) { + printer->Print( + "from google.protobuf import service\n" + "from google.protobuf import service_reflection\n"); + } + // Avoid circular imports if this module is descriptor_pb2. if (!descriptor_proto) { printer->Print( "from google.protobuf import descriptor_pb2\n"); } + printer->Print( + "# @@protoc_insertion_point(imports)\n"); + printer->Print("\n\n"); } @@ -150,10 +165,30 @@ string StringifyDefaultValue(const FieldDescriptor& field) { return SimpleItoa(field.default_value_int64()); case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(field.default_value_uint64()); - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field.default_value_double()); - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field.default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field.default_value_double(); + if (value == numeric_limits::infinity()) { + return "float('inf')"; + } else if (value == -numeric_limits::infinity()) { + return "float('-inf')"; + } else if (value != value) { + return "float('nan')"; + } else { + return SimpleDtoa(value); + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field.default_value_float(); + if (value == numeric_limits::infinity()) { + return "float('inf')"; + } else if (value == -numeric_limits::infinity()) { + return "float('-inf')"; + } else if (value != value) { + return "float('nan')"; + } else { + return SimpleFtoa(value); + } + } case FieldDescriptor::CPPTYPE_BOOL: return field.default_value_bool() ? "True" : "False"; case FieldDescriptor::CPPTYPE_ENUM: @@ -204,6 +239,10 @@ bool Generator::Generate(const FileDescriptor* file, StripString(&filename, ".", '/'); filename += ".py"; + FileDescriptorProto fdp; + file_->CopyTo(&fdp); + fdp.SerializeToString(&file_descriptor_serialized_); + scoped_ptr output(output_directory->Open(filename)); GOOGLE_CHECK(output.get()); @@ -211,6 +250,7 @@ bool Generator::Generate(const FileDescriptor* file, printer_ = &printer; PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto()); + PrintFileDescriptor(); PrintTopLevelEnums(); PrintTopLevelExtensions(); PrintAllNestedEnumsInFile(); @@ -224,7 +264,13 @@ bool Generator::Generate(const FileDescriptor* file, // since they need to call static RegisterExtension() methods on these // classes. FixForeignFieldsInExtensions(); - PrintServices(); + if (HasGenericServices(file)) { + PrintServices(); + } + + printer.Print( + "# @@protoc_insertion_point(module_scope)\n"); + return !printer.failed(); } @@ -238,6 +284,30 @@ void Generator::PrintImports() const { printer_->Print("\n"); } +// Prints the single file descriptor for this file. +void Generator::PrintFileDescriptor() const { + map m; + m["descriptor_name"] = kDescriptorKey; + m["name"] = file_->name(); + m["package"] = file_->package(); + const char file_descriptor_template[] = + "$descriptor_name$ = descriptor.FileDescriptor(\n" + " name='$name$',\n" + " package='$package$',\n"; + printer_->Print(m, file_descriptor_template); + printer_->Indent(); + printer_->Print( + "serialized_pb='$value$'", + "value", strings::CHexEscape(file_descriptor_serialized_)); + + // TODO(falk): Also print options and fix the message_type, enum_type, + // service and extension later in the generation. + + printer_->Outdent(); + printer_->Print(")\n"); + printer_->Print("\n"); +} + // Prints descriptors and module-level constants for all top-level // enums defined in |file|. void Generator::PrintTopLevelEnums() const { @@ -277,12 +347,13 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor); m["name"] = enum_descriptor.name(); m["full_name"] = enum_descriptor.full_name(); - m["filename"] = enum_descriptor.name(); + m["file"] = kDescriptorKey; const char enum_descriptor_template[] = "$descriptor_name$ = descriptor.EnumDescriptor(\n" " name='$name$',\n" " full_name='$full_name$',\n" - " filename='$filename$',\n" + " filename=None,\n" + " file=$file$,\n" " values=[\n"; string options_string; enum_descriptor.options().SerializeToString(&options_string); @@ -295,9 +366,12 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { } printer_->Outdent(); printer_->Print("],\n"); + printer_->Print("containing_type=None,\n"); printer_->Print("options=$options_value$,\n", "options_value", OptionsValue("EnumOptions", CEscape(options_string))); + EnumDescriptorProto edp; + PrintSerializedPbInterval(enum_descriptor, edp); printer_->Outdent(); printer_->Print(")\n"); printer_->Print("\n"); @@ -362,15 +436,21 @@ void Generator::PrintServiceDescriptor( map m; m["name"] = descriptor.name(); m["full_name"] = descriptor.full_name(); + m["file"] = kDescriptorKey; m["index"] = SimpleItoa(descriptor.index()); m["options_value"] = OptionsValue("ServiceOptions", options_string); const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" + "file=$file$,\n" "index=$index$,\n" - "options=$options_value$,\n" - "methods=[\n"; + "options=$options_value$,\n"; printer_->Print(m, required_function_arguments); + + ServiceDescriptorProto sdp; + PrintSerializedPbInterval(descriptor, sdp); + + printer_->Print("methods=[\n"); for (int i = 0; i < descriptor.method_count(); ++i) { const MethodDescriptor* method = descriptor.method(i); string options_string; @@ -444,17 +524,27 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { map m; m["name"] = message_descriptor.name(); m["full_name"] = message_descriptor.full_name(); - m["filename"] = message_descriptor.file()->name(); + m["file"] = kDescriptorKey; const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" - "filename='$filename$',\n" - "containing_type=None,\n"; // TODO(robinson): Implement containing_type. + "filename=None,\n" + "file=$file$,\n" + "containing_type=None,\n"; printer_->Print(m, required_function_arguments); PrintFieldsInDescriptor(message_descriptor); PrintExtensionsInDescriptor(message_descriptor); - // TODO(robinson): implement printing of nested_types. - printer_->Print("nested_types=[], # TODO(robinson): Implement.\n"); + + // Nested types + printer_->Print("nested_types=["); + for (int i = 0; i < message_descriptor.nested_type_count(); ++i) { + const string nested_name = ModuleLevelDescriptorName( + *message_descriptor.nested_type(i)); + printer_->Print("$name$, ", "name", nested_name); + } + printer_->Print("],\n"); + + // Enum types printer_->Print("enum_types=[\n"); printer_->Indent(); for (int i = 0; i < message_descriptor.enum_type_count(); ++i) { @@ -468,8 +558,28 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { string options_string; message_descriptor.options().SerializeToString(&options_string); printer_->Print( - "options=$options_value$", - "options_value", OptionsValue("MessageOptions", options_string)); + "options=$options_value$,\n" + "is_extendable=$extendable$", + "options_value", OptionsValue("MessageOptions", options_string), + "extendable", message_descriptor.extension_range_count() > 0 ? + "True" : "False"); + printer_->Print(",\n"); + + // Extension ranges + printer_->Print("extension_ranges=["); + for (int i = 0; i < message_descriptor.extension_range_count(); ++i) { + const Descriptor::ExtensionRange* range = + message_descriptor.extension_range(i); + printer_->Print("($start$, $end$), ", + "start", SimpleItoa(range->start), + "end", SimpleItoa(range->end)); + } + printer_->Print("],\n"); + + // Serialization of proto + DescriptorProto edp; + PrintSerializedPbInterval(message_descriptor, edp); + printer_->Outdent(); printer_->Print(")\n"); } @@ -511,6 +621,12 @@ void Generator::PrintMessage( m["descriptor_key"] = kDescriptorKey; m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); printer_->Print(m, "$descriptor_key$ = $descriptor_name$\n"); + + printer_->Print( + "\n" + "# @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", message_descriptor.full_name()); + printer_->Outdent(); } @@ -527,16 +643,27 @@ void Generator::PrintNestedMessages( // Recursively fixes foreign fields in all nested types in |descriptor|, then // sets the message_type and enum_type of all message and enum fields to point // to their respective descriptors. +// Args: +// descriptor: descriptor to print fields for. +// containing_descriptor: if descriptor is a nested type, this is its +// containing type, or NULL if this is a root/top-level type. void Generator::FixForeignFieldsInDescriptor( - const Descriptor& descriptor) const { + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const { for (int i = 0; i < descriptor.nested_type_count(); ++i) { - FixForeignFieldsInDescriptor(*descriptor.nested_type(i)); + FixForeignFieldsInDescriptor(*descriptor.nested_type(i), &descriptor); } for (int i = 0; i < descriptor.field_count(); ++i) { const FieldDescriptor& field_descriptor = *descriptor.field(i); FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name"); } + + FixContainingTypeInDescriptor(descriptor, containing_descriptor); + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i); + FixContainingTypeInDescriptor(enum_descriptor, &descriptor); + } } // Sets any necessary message_type and enum_type attributes @@ -593,13 +720,29 @@ string Generator::FieldReferencingExpression( python_dict_name, field.name()); } +// Prints containing_type for nested descriptors or enum descriptors. +template +void Generator::FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const { + if (containing_descriptor != NULL) { + const string nested_name = ModuleLevelDescriptorName(descriptor); + const string parent_name = ModuleLevelDescriptorName( + *containing_descriptor); + printer_->Print( + "$nested_name$.containing_type = $parent_name$;\n", + "nested_name", nested_name, + "parent_name", parent_name); + } +} + // Prints statements setting the message_type and enum_type fields in the // Python descriptor objects we've already output in ths file. We must // do this in a separate step due to circular references (otherwise, we'd // just set everything in the initial assignment statements). void Generator::FixForeignFieldsInDescriptors() const { for (int i = 0; i < file_->message_type_count(); ++i) { - FixForeignFieldsInDescriptor(*file_->message_type(i)); + FixForeignFieldsInDescriptor(*file_->message_type(i), NULL); } printer_->Print("\n"); } @@ -696,6 +839,7 @@ void Generator::PrintFieldDescriptor( m["type"] = SimpleItoa(field.type()); m["cpp_type"] = SimpleItoa(field.cpp_type()); m["label"] = SimpleItoa(field.label()); + m["has_default_value"] = field.has_default_value() ? "True" : "False"; m["default_value"] = StringifyDefaultValue(field); m["is_extension"] = is_extension ? "True" : "False"; m["options"] = OptionsValue("FieldOptions", options_string); @@ -703,13 +847,13 @@ void Generator::PrintFieldDescriptor( // these fields in correctly after all referenced descriptors have been // defined and/or imported (see FixForeignFieldsInDescriptors()). const char field_descriptor_decl[] = - "descriptor.FieldDescriptor(\n" - " name='$name$', full_name='$full_name$', index=$index$,\n" - " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" - " default_value=$default_value$,\n" - " message_type=None, enum_type=None, containing_type=None,\n" - " is_extension=$is_extension$, extension_scope=None,\n" - " options=$options$)"; + "descriptor.FieldDescriptor(\n" + " name='$name$', full_name='$full_name$', index=$index$,\n" + " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" + " has_default_value=$has_default_value$, default_value=$default_value$,\n" + " message_type=None, enum_type=None, containing_type=None,\n" + " is_extension=$is_extension$, extension_scope=None,\n" + " options=$options$)"; printer_->Print(m, field_descriptor_decl); } @@ -811,6 +955,29 @@ string Generator::ModuleLevelServiceDescriptorName( return name; } +// Prints standard constructor arguments serialized_start and serialized_end. +// Args: +// descriptor: The cpp descriptor to have a serialized reference. +// proto: A proto +// Example printer output: +// serialized_start=41, +// serialized_end=43, +// +template +void Generator::PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const { + descriptor.CopyTo(&proto); + string sp; + proto.SerializeToString(&sp); + int offset = file_descriptor_serialized_.find(sp); + GOOGLE_CHECK_GE(offset, 0); + + printer_->Print("serialized_start=$serialized_start$,\n" + "serialized_end=$serialized_end$,\n", + "serialized_start", SimpleItoa(offset), + "serialized_end", SimpleItoa(offset + sp.size())); +} + } // namespace python } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 8b99d624..43c20876 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -71,6 +71,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { private: void PrintImports() const; + void PrintFileDescriptor() const; void PrintTopLevelEnums() const; void PrintAllNestedEnumsInFile() const; void PrintNestedEnums(const Descriptor& descriptor) const; @@ -97,13 +98,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { void PrintNestedMessages(const Descriptor& containing_descriptor) const; void FixForeignFieldsInDescriptors() const; - void FixForeignFieldsInDescriptor(const Descriptor& descriptor) const; + void FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInField(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; string FieldReferencingExpression(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; + template + void FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInExtensions() const; void FixForeignFieldsInExtension( @@ -126,10 +133,15 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { string ModuleLevelServiceDescriptorName( const ServiceDescriptor& descriptor) const; + template + void PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const; + // Very coarse-grained lock to ensure that Generate() is reentrant. - // Guards file_ and printer_. + // Guards file_, printer_ and file_descriptor_serialized_. mutable Mutex mutex_; mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable string file_descriptor_serialized_; mutable io::Printer* printer_; // Set in Generate(). Under mutex_. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index a12e4e72..e0a95077 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -796,9 +796,10 @@ bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { 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_; @@ -810,6 +811,7 @@ void DeleteGeneratedPool() { void InitGeneratedPool() { generated_database_ = new EncodedDescriptorDatabase; generated_pool_ = new DescriptorPool(generated_database_); + internal::OnShutdown(&DeleteGeneratedPool); } @@ -3651,17 +3653,11 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, } // Only repeated primitive fields may be packed. - if (field->options().packed()) { - if (!field->is_repeated() || - field->type() == FieldDescriptor::TYPE_STRING || - field->type() == FieldDescriptor::TYPE_GROUP || - field->type() == FieldDescriptor::TYPE_MESSAGE || - field->type() == FieldDescriptor::TYPE_BYTES) { - AddError( - field->full_name(), proto, - DescriptorPool::ErrorCollector::TYPE, - "[packed = true] can only be specified for repeated primitive fields."); - } + if (field->options().packed() && !field->is_packable()) { + AddError( + field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "[packed = true] can only be specified for repeated primitive fields."); } // Note: Default instance may not yet be initialized here, so we have to diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 5b629a5d..7f87dd80 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -395,6 +395,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { bool is_required() const; // shorthand for label() == LABEL_REQUIRED bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL bool is_repeated() const; // shorthand for label() == LABEL_REPEATED + bool is_packable() const; // shorthand for is_repeated() && + // IsTypePackable(type()) // Index of this field within the message's field array, or the file or // extension scope's extensions array. @@ -474,6 +476,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // Helper method to get the CppType for a particular Type. static CppType TypeToCppType(Type type); + // Return true iff [packed = true] is valid for fields of this type. + static inline bool IsTypePackable(Type field_type); + private: typedef FieldOptions OptionsType; @@ -1069,10 +1074,6 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // These methods may contain hidden pitfalls and may be removed in a // future library version. - // DEPRECATED: Use of underlays can lead to many subtle gotchas. Instead, - // try to formulate what you want to do in terms of DescriptorDatabases. - // This constructor will be removed soon. - // // Create a DescriptorPool which is overlaid on top of some other pool. // If you search for a descriptor in the overlay and it is not found, the // underlay will be searched as a backup. If the underlay has its own @@ -1090,6 +1091,9 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // types directly into generated_pool(): this is not allowed, and would be // bad design anyway. So, instead, you could use generated_pool() as an // underlay for a new DescriptorPool in which you add only the new file. + // + // WARNING: Use of underlays can lead to many subtle gotchas. Instead, + // try to formulate what you want to do in terms of DescriptorDatabases. explicit DescriptorPool(const DescriptorPool* underlay); // Called by generated classes at init time to add their descriptors to @@ -1294,6 +1298,10 @@ inline bool FieldDescriptor::is_repeated() const { return label() == LABEL_REPEATED; } +inline bool FieldDescriptor::is_packable() const { + return is_repeated() && IsTypePackable(type()); +} + // To save space, index() is computed by looking at the descriptor's position // in the parent's array of children. inline int FieldDescriptor::index() const { @@ -1342,6 +1350,13 @@ inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { return kTypeToCppTypeMap[type]; } +inline bool FieldDescriptor::IsTypePackable(Type field_type) { + return (field_type != FieldDescriptor::TYPE_STRING && + field_type != FieldDescriptor::TYPE_GROUP && + field_type != FieldDescriptor::TYPE_MESSAGE && + field_type != FieldDescriptor::TYPE_BYTES); +} + inline const FileDescriptor* FileDescriptor::dependency(int index) const { return dependencies_[index]; } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 276c6009..f61e7cd0 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -8,6 +8,7 @@ #include #include #include +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -250,11 +251,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { ::google::protobuf::MessageFactory::generated_factory(), sizeof(MethodDescriptorProto)); FileOptions_descriptor_ = file->message_type(8); - static const int FileOptions_offsets_[5] = { + static const int FileOptions_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -552,43 +556,47 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "ptions\"\177\n\025MethodDescriptorProto\022\014\n\004name\030" "\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output_type" "\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.protobu" - "f.MethodOptions\"\271\002\n\013FileOptions\022\024\n\014java_" + "f.MethodOptions\"\244\003\n\013FileOptions\022\024\n\014java_" "package\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 " "\001(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022" "F\n\014optimize_for\030\t \001(\0162).google.protobuf." - "FileOptions.OptimizeMode:\005SPEED\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" - "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" - "*\t\010\350\007\020\200\200\200\200\002\"\270\001\n\016MessageOptions\022&\n\027messag" - "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" - "ndard_descriptor_accessor\030\002 \001(\010:\005false\022C" - "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" - "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\200" - "\002\n\014FieldOptions\0222\n\005ctype\030\001 \001(\0162#.google." - "protobuf.FieldOptions.CType\022\016\n\006packed\030\002 " - "\001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experi" - "mental_map_key\030\t \001(\t\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_P" - "IECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024unin" - "terpreted_option\030\347\007 \003(\0132$.google.protobu" - "f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020Enum" - "ValueOptions\022C\n\024uninterpreted_option\030\347\007 " - "\003(\0132$.google.protobuf.UninterpretedOptio" - "n*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninte" - "rpreted_option\030\347\007 \003(\0132$.google.protobuf." - "UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethod" - "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$" - ".google.protobuf.UninterpretedOption*\t\010\350" - "\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;\n\004name\030" - "\002 \003(\0132-.google.protobuf.UninterpretedOpt" - "ion.NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032" - "\n\022positive_int_value\030\004 \001(\004\022\032\n\022negative_i" - "nt_value\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014" - "string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_p" - "art\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.g" - "oogle.protobufB\020DescriptorProtosH\001", 3554); + "FileOptions.OptimizeMode:\005SPEED\022!\n\023cc_ge" + "neric_services\030\020 \001(\010:\004true\022#\n\025java_gener" + "ic_services\030\021 \001(\010:\004true\022!\n\023py_generic_se" + "rvices\030\022 \001(\010:\004true\022C\n\024uninterpreted_opti" + "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete" + "dOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCO" + "DE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\270" + "\001\n\016MessageOptions\022&\n\027message_set_wire_fo" + "rmat\030\001 \001(\010:\005false\022.\n\037no_standard_descrip" + "tor_accessor\030\002 \001(\010:\005false\022C\n\024uninterpret" + "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" + "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptio" + "ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel" + "dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experimenta" + "l_map_key\030\t \001(\t\022C\n\024uninterpreted_option\030" + "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" + "tion\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014S" + "TRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022" + "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." + "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" + "b\n\020EnumValueOptions\022C\n\024uninterpreted_opt" + "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" + "edOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n" + "\024uninterpreted_option\030\347\007 \003(\0132$.google.pr" + "otobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n" + "\rMethodOptions\022C\n\024uninterpreted_option\030\347" + "\007 \003(\0132$.google.protobuf.UninterpretedOpt" + "ion*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;" + "\n\004name\030\002 \003(\0132-.google.protobuf.Uninterpr" + "etedOption.NamePart\022\030\n\020identifier_value\030" + "\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022neg" + "ative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006 " + "\001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n" + "\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)" + "\n\023com.google.protobufB\020DescriptorProtosH" + "\001", 3681); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -645,7 +653,7 @@ const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER FileDescriptorSet::FileDescriptorSet() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -653,7 +661,7 @@ void FileDescriptorSet::InitAsDefaultInstance() { } FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -672,6 +680,11 @@ void FileDescriptorSet::SharedDtor() { } } +void FileDescriptorSet::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorSet_descriptor_; @@ -701,13 +714,14 @@ bool FileDescriptorSet::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.FileDescriptorProto file = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { goto handle_uninterpreted; } - parse_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_file())); if (input->ExpectTag(10)) goto parse_file; if (input->ExpectAtEnd()) return true; break; @@ -731,15 +745,9 @@ bool FileDescriptorSet::MergePartialFromCodedStream( void FileDescriptorSet::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorSet::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.FileDescriptorProto file = 1; for (int i = 0; i < this->file_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 1, this->file(i), output); } @@ -781,7 +789,9 @@ int FileDescriptorSet::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -857,7 +867,7 @@ const int FileDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FileDescriptorProto::FileDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -866,7 +876,7 @@ void FileDescriptorProto::InitAsDefaultInstance() { } FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -895,6 +905,11 @@ void FileDescriptorProto::SharedDtor() { } } +void FileDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorProto_descriptor_; @@ -943,47 +958,50 @@ bool FileDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_package; break; } // optional string package = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_package: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_package: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->package().data(), this->package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; break; } // repeated string dependency = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_dependency: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_dependency())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(0).data(), this->dependency(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_dependency: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->add_dependency())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->dependency(0).data(), this->dependency(0).length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; if (input->ExpectTag(34)) goto parse_message_type; break; @@ -991,13 +1009,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto message_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_message_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_message_type())); + } else { goto handle_uninterpreted; } - parse_message_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_message_type())); if (input->ExpectTag(34)) goto parse_message_type; if (input->ExpectTag(42)) goto parse_enum_type; break; @@ -1005,13 +1024,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(42)) goto parse_enum_type; if (input->ExpectTag(50)) goto parse_service; break; @@ -1019,13 +1039,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.ServiceDescriptorProto service = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_service: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_service())); + } else { goto handle_uninterpreted; } - parse_service: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_service())); if (input->ExpectTag(50)) goto parse_service; if (input->ExpectTag(58)) goto parse_extension; break; @@ -1033,13 +1054,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(58)) goto parse_extension; if (input->ExpectTag(66)) goto parse_options; break; @@ -1047,13 +1069,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FileOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1076,12 +1099,6 @@ bool FileDescriptorProto::MergePartialFromCodedStream( void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1111,31 +1128,31 @@ void FileDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.DescriptorProto message_type = 4; for (int i = 0; i < this->message_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->message_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->enum_type(i), output); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; for (int i = 0; i < this->service_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->service(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->extension(i), output); } // optional .google.protobuf.FileOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -1288,7 +1305,9 @@ int FileDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1390,7 +1409,7 @@ const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -1398,7 +1417,7 @@ void DescriptorProto_ExtensionRange::InitAsDefaultInstance() { } DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1419,6 +1438,11 @@ void DescriptorProto_ExtensionRange::SharedDtor() { } } +void DescriptorProto_ExtensionRange::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_ExtensionRange_descriptor_; @@ -1451,27 +1475,31 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional int32 start = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &start_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &start_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_end; break; } // optional int32 end = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_end: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &end_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -1494,12 +1522,6 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional int32 start = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output); @@ -1559,7 +1581,9 @@ int DescriptorProto_ExtensionRange::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1638,7 +1662,7 @@ const int DescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER DescriptorProto::DescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -1647,7 +1671,7 @@ void DescriptorProto::InitAsDefaultInstance() { } DescriptorProto::DescriptorProto(const DescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1672,6 +1696,11 @@ void DescriptorProto::SharedDtor() { } } +void DescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_descriptor_; @@ -1715,28 +1744,30 @@ bool DescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_field; break; } // repeated .google.protobuf.FieldDescriptorProto field = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_field: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_field())); + } else { goto handle_uninterpreted; } - parse_field: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_field())); if (input->ExpectTag(18)) goto parse_field; if (input->ExpectTag(26)) goto parse_nested_type; break; @@ -1744,13 +1775,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto nested_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_nested_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_nested_type())); + } else { goto handle_uninterpreted; } - parse_nested_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_nested_type())); if (input->ExpectTag(26)) goto parse_nested_type; if (input->ExpectTag(34)) goto parse_enum_type; break; @@ -1758,13 +1790,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(34)) goto parse_enum_type; if (input->ExpectTag(42)) goto parse_extension_range; break; @@ -1772,13 +1805,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension_range())); + } else { goto handle_uninterpreted; } - parse_extension_range: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension_range())); if (input->ExpectTag(42)) goto parse_extension_range; if (input->ExpectTag(50)) goto parse_extension; break; @@ -1786,13 +1820,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(50)) goto parse_extension; if (input->ExpectTag(58)) goto parse_options; break; @@ -1800,13 +1835,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.MessageOptions options = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1829,12 +1865,6 @@ bool DescriptorProto::MergePartialFromCodedStream( void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1846,37 +1876,37 @@ void DescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.FieldDescriptorProto field = 2; for (int i = 0; i < this->field_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->field(i), output); } // repeated .google.protobuf.DescriptorProto nested_type = 3; for (int i = 0; i < this->nested_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->nested_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->enum_type(i), output); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; for (int i = 0; i < this->extension_range_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->extension_range(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->extension(i), output); } // optional .google.protobuf.MessageOptions options = 7; if (_has_bit(6)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->options(), output); } @@ -2011,7 +2041,9 @@ int DescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2154,6 +2186,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32; const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; +const int FieldDescriptorProto::Type_ARRAYSIZE; #endif // _MSC_VER const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { protobuf_AssignDescriptorsOnce(); @@ -2176,6 +2209,7 @@ const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; +const int FieldDescriptorProto::Label_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldDescriptorProto::_default_name_; const ::std::string FieldDescriptorProto::_default_type_name_; @@ -2193,7 +2227,7 @@ const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FieldDescriptorProto::FieldDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -2202,7 +2236,7 @@ void FieldDescriptorProto::InitAsDefaultInstance() { } FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2242,6 +2276,11 @@ void FieldDescriptorProto::SharedDtor() { } } +void FieldDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_descriptor_; @@ -2298,62 +2337,69 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_extendee; break; } // optional string extendee = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extendee: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_extendee())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_extendee: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_extendee())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->extendee().data(), this->extendee().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(24)) goto parse_number; break; } // optional int32 number = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(32)) goto parse_label; break; } // optional .google.protobuf.FieldDescriptorProto.Label label = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_label: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { - set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + parse_label: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { + set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + } else { + mutable_unknown_fields()->AddVarint(4, value); + } } else { - mutable_unknown_fields()->AddVarint(4, value); + goto handle_uninterpreted; } if (input->ExpectTag(40)) goto parse_type; break; @@ -2361,17 +2407,20 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FieldDescriptorProto.Type type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_type: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { - set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { + set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + } else { + mutable_unknown_fields()->AddVarint(5, value); + } } else { - mutable_unknown_fields()->AddVarint(5, value); + goto handle_uninterpreted; } if (input->ExpectTag(50)) goto parse_type_name; break; @@ -2379,45 +2428,48 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional string type_name = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_type_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_type_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_type_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_type_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->type_name().data(), this->type_name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(58)) goto parse_default_value; break; } // optional string default_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_default_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_default_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_default_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_default_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->default_value().data(), this->default_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_options; break; } // optional .google.protobuf.FieldOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2440,12 +2492,6 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2501,7 +2547,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.FieldOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -2648,7 +2694,9 @@ int FieldDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2750,7 +2798,7 @@ const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumDescriptorProto::EnumDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -2759,7 +2807,7 @@ void EnumDescriptorProto::InitAsDefaultInstance() { } EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2784,6 +2832,11 @@ void EnumDescriptorProto::SharedDtor() { } } +void EnumDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumDescriptorProto_descriptor_; @@ -2823,28 +2876,30 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_value; break; } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_value())); + } else { goto handle_uninterpreted; } - parse_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_value())); if (input->ExpectTag(18)) goto parse_value; if (input->ExpectTag(26)) goto parse_options; break; @@ -2852,13 +2907,14 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.EnumOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2881,12 +2937,6 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2898,13 +2948,13 @@ void EnumDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.EnumValueDescriptorProto value = 2; for (int i = 0; i < this->value_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->value(i), output); } // optional .google.protobuf.EnumOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -2979,7 +3029,9 @@ int EnumDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3062,7 +3114,7 @@ const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumValueDescriptorProto::EnumValueDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3071,7 +3123,7 @@ void EnumValueDescriptorProto::InitAsDefaultInstance() { } EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3097,6 +3149,11 @@ void EnumValueDescriptorProto::SharedDtor() { } } +void EnumValueDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueDescriptorProto_descriptor_; @@ -3136,42 +3193,46 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_number; break; } // optional int32 number = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(26)) goto parse_options; break; } // optional .google.protobuf.EnumValueOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3194,12 +3255,6 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3216,7 +3271,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.EnumValueOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3288,7 +3343,9 @@ int EnumValueDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3370,7 +3427,7 @@ const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER ServiceDescriptorProto::ServiceDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3379,7 +3436,7 @@ void ServiceDescriptorProto::InitAsDefaultInstance() { } ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3404,6 +3461,11 @@ void ServiceDescriptorProto::SharedDtor() { } } +void ServiceDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceDescriptorProto_descriptor_; @@ -3443,28 +3505,30 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_method; break; } // repeated .google.protobuf.MethodDescriptorProto method = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_method: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_method())); + } else { goto handle_uninterpreted; } - parse_method: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_method())); if (input->ExpectTag(18)) goto parse_method; if (input->ExpectTag(26)) goto parse_options; break; @@ -3472,13 +3536,14 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.ServiceOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3501,12 +3566,6 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3518,13 +3577,13 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.MethodDescriptorProto method = 2; for (int i = 0; i < this->method_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->method(i), output); } // optional .google.protobuf.ServiceOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3599,7 +3658,9 @@ int ServiceDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3685,7 +3746,7 @@ const int MethodDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3694,7 +3755,7 @@ void MethodDescriptorProto::InitAsDefaultInstance() { } MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3727,6 +3788,11 @@ void MethodDescriptorProto::SharedDtor() { } } +void MethodDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodDescriptorProto_descriptor_; @@ -3775,60 +3841,64 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_input_type; break; } // optional string input_type = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_input_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_input_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_input_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_input_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->input_type().data(), this->input_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_output_type; break; } // optional string output_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_output_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_output_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_output_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_output_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->output_type().data(), this->output_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(34)) goto parse_options; break; } // optional .google.protobuf.MethodOptions options = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3851,12 +3921,6 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3886,7 +3950,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.MethodOptions options = 4; if (_has_bit(3)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->options(), output); } @@ -3980,7 +4044,9 @@ int MethodDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4079,6 +4145,7 @@ const FileOptions_OptimizeMode FileOptions::CODE_SIZE; const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; +const int FileOptions::OptimizeMode_ARRAYSIZE; #endif // _MSC_VER const ::std::string FileOptions::_default_java_package_; const ::std::string FileOptions::_default_java_outer_classname_; @@ -4087,11 +4154,14 @@ const int FileOptions::kJavaPackageFieldNumber; const int FileOptions::kJavaOuterClassnameFieldNumber; const int FileOptions::kJavaMultipleFilesFieldNumber; const int FileOptions::kOptimizeForFieldNumber; +const int FileOptions::kCcGenericServicesFieldNumber; +const int FileOptions::kJavaGenericServicesFieldNumber; +const int FileOptions::kPyGenericServicesFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FileOptions::FileOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4099,7 +4169,7 @@ void FileOptions::InitAsDefaultInstance() { } FileOptions::FileOptions(const FileOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4110,6 +4180,9 @@ void FileOptions::SharedCtor() { java_outer_classname_ = const_cast< ::std::string*>(&_default_java_outer_classname_); java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4128,6 +4201,11 @@ void FileOptions::SharedDtor() { } } +void FileOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FileOptions_descriptor_; @@ -4158,6 +4236,9 @@ void FileOptions::Clear() { } java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; } uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -4172,48 +4253,53 @@ bool FileOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string java_package = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_package().data(), this->java_package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_java_outer_classname; break; } // optional string java_outer_classname = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_java_outer_classname: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_outer_classname())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_java_outer_classname: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_outer_classname())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_outer_classname().data(), this->java_outer_classname().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(72)) goto parse_optimize_for; break; } // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_optimize_for: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { - set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + parse_optimize_for: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { + set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + } else { + mutable_unknown_fields()->AddVarint(9, value); + } } else { - mutable_unknown_fields()->AddVarint(9, value); + goto handle_uninterpreted; } if (input->ExpectTag(80)) goto parse_java_multiple_files; break; @@ -4221,27 +4307,78 @@ bool FileOptions::MergePartialFromCodedStream( // optional bool java_multiple_files = 10 [default = false]; case 10: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_multiple_files: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_multiple_files_))); + _set_bit(2); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(128)) goto parse_cc_generic_services; + break; + } + + // optional bool cc_generic_services = 16 [default = true]; + case 16: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_cc_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &cc_generic_services_))); + _set_bit(4); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(136)) goto parse_java_generic_services; + break; + } + + // optional bool java_generic_services = 17 [default = true]; + case 17: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_generic_services_))); + _set_bit(5); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(144)) goto parse_py_generic_services; + break; + } + + // optional bool py_generic_services = 18 [default = true]; + case 18: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_py_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &py_generic_services_))); + _set_bit(6); + } else { goto handle_uninterpreted; } - parse_java_multiple_files: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &java_multiple_files_)); - _set_bit(2); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4270,12 +4407,6 @@ bool FileOptions::MergePartialFromCodedStream( void FileOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string java_package = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -4305,9 +4436,24 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4354,6 +4500,21 @@ void FileOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -4401,6 +4562,21 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for()); } + // optional bool cc_generic_services = 16 [default = true]; + if (has_cc_generic_services()) { + total_size += 2 + 1; + } + + // optional bool java_generic_services = 17 [default = true]; + if (has_java_generic_services()) { + total_size += 2 + 1; + } + + // optional bool py_generic_services = 18 [default = true]; + if (has_py_generic_services()) { + total_size += 2 + 1; + } + } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -4417,7 +4593,9 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4449,6 +4627,15 @@ void FileOptions::MergeFrom(const FileOptions& from) { if (from._has_bit(3)) { set_optimize_for(from.optimize_for()); } + if (from._has_bit(4)) { + set_cc_generic_services(from.cc_generic_services()); + } + if (from._has_bit(5)) { + set_java_generic_services(from.java_generic_services()); + } + if (from._has_bit(6)) { + set_py_generic_services(from.py_generic_services()); + } } _extensions_.MergeFrom(from._extensions_); mutable_unknown_fields()->MergeFrom(from.unknown_fields()); @@ -4481,6 +4668,9 @@ void FileOptions::Swap(FileOptions* other) { std::swap(java_outer_classname_, other->java_outer_classname_); std::swap(java_multiple_files_, other->java_multiple_files_); std::swap(optimize_for_, other->optimize_for_); + std::swap(cc_generic_services_, other->cc_generic_services_); + std::swap(java_generic_services_, other->java_generic_services_); + std::swap(py_generic_services_, other->py_generic_services_); uninterpreted_option_.Swap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); @@ -4507,7 +4697,7 @@ const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MessageOptions::MessageOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4515,7 +4705,7 @@ void MessageOptions::InitAsDefaultInstance() { } MessageOptions::MessageOptions(const MessageOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4536,6 +4726,11 @@ void MessageOptions::SharedDtor() { } } +void MessageOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MessageOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MessageOptions_descriptor_; @@ -4570,40 +4765,45 @@ bool MessageOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional bool message_set_wire_format = 1 [default = false]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &message_set_wire_format_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &message_set_wire_format_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor; break; } // optional bool no_standard_descriptor_accessor = 2 [default = false]; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_no_standard_descriptor_accessor: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &no_standard_descriptor_accessor_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_no_standard_descriptor_accessor: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &no_standard_descriptor_accessor_)); - _set_bit(1); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4632,12 +4832,6 @@ bool MessageOptions::MergePartialFromCodedStream( void MessageOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MessageOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional bool message_set_wire_format = 1 [default = false]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output); @@ -4650,7 +4844,7 @@ void MessageOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4724,7 +4918,9 @@ int MessageOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4805,6 +5001,7 @@ const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() { } bool FieldOptions_CType_IsValid(int value) { switch(value) { + case 0: case 1: case 2: return true; @@ -4814,10 +5011,12 @@ bool FieldOptions_CType_IsValid(int value) { } #ifndef _MSC_VER +const FieldOptions_CType FieldOptions::STRING; const FieldOptions_CType FieldOptions::CORD; const FieldOptions_CType FieldOptions::STRING_PIECE; const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; +const int FieldOptions::CType_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldOptions::_default_experimental_map_key_; #ifndef _MSC_VER @@ -4829,7 +5028,7 @@ const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FieldOptions::FieldOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4837,14 +5036,14 @@ void FieldOptions::InitAsDefaultInstance() { } FieldOptions::FieldOptions(const FieldOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } void FieldOptions::SharedCtor() { _cached_size_ = 0; - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; experimental_map_key_ = const_cast< ::std::string*>(&_default_experimental_map_key_); @@ -4863,6 +5062,11 @@ void FieldOptions::SharedDtor() { } } +void FieldOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldOptions_descriptor_; @@ -4881,7 +5085,7 @@ FieldOptions* FieldOptions::New() const { void FieldOptions::Clear() { _extensions_.Clear(); if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; if (_has_bit(3)) { @@ -4901,18 +5105,21 @@ bool FieldOptions::MergePartialFromCodedStream( ::google::protobuf::uint32 tag; while ((tag = input->ReadTag()) != 0) { switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldOptions_CType_IsValid(value)) { - set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldOptions_CType_IsValid(value)) { + set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + } else { + mutable_unknown_fields()->AddVarint(1, value); + } } else { - mutable_unknown_fields()->AddVarint(1, value); + goto handle_uninterpreted; } if (input->ExpectTag(16)) goto parse_packed; break; @@ -4920,57 +5127,63 @@ bool FieldOptions::MergePartialFromCodedStream( // optional bool packed = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_packed: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &packed_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_packed: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &packed_)); - _set_bit(1); if (input->ExpectTag(24)) goto parse_deprecated; break; } // optional bool deprecated = 3 [default = false]; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_deprecated: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &deprecated_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_deprecated: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &deprecated_)); - _set_bit(2); if (input->ExpectTag(74)) goto parse_experimental_map_key; break; } // optional string experimental_map_key = 9; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_experimental_map_key: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_experimental_map_key())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_experimental_map_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_experimental_map_key())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4999,13 +5212,7 @@ bool FieldOptions::MergePartialFromCodedStream( void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteEnum( 1, this->ctype(), output); @@ -5032,7 +5239,7 @@ void FieldOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5048,7 +5255,7 @@ void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray( ::google::protobuf::uint8* target) const { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( 1, this->ctype(), target); @@ -5096,7 +5303,7 @@ int FieldOptions::ByteSize() const { int total_size = 0; if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (has_ctype()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype()); @@ -5135,7 +5342,9 @@ int FieldOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5223,7 +5432,7 @@ const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumOptions::EnumOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5231,7 +5440,7 @@ void EnumOptions::InitAsDefaultInstance() { } EnumOptions::EnumOptions(const EnumOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5250,6 +5459,11 @@ void EnumOptions::SharedDtor() { } } +void EnumOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumOptions_descriptor_; @@ -5280,13 +5494,14 @@ bool EnumOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5315,15 +5530,9 @@ bool EnumOptions::MergePartialFromCodedStream( void EnumOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5375,7 +5584,9 @@ int EnumOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5445,7 +5656,7 @@ const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumValueOptions::EnumValueOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5453,7 +5664,7 @@ void EnumValueOptions::InitAsDefaultInstance() { } EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5472,6 +5683,11 @@ void EnumValueOptions::SharedDtor() { } } +void EnumValueOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueOptions_descriptor_; @@ -5502,13 +5718,14 @@ bool EnumValueOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5537,15 +5754,9 @@ bool EnumValueOptions::MergePartialFromCodedStream( void EnumValueOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5597,7 +5808,9 @@ int EnumValueOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5667,7 +5880,7 @@ const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER ServiceOptions::ServiceOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5675,7 +5888,7 @@ void ServiceOptions::InitAsDefaultInstance() { } ServiceOptions::ServiceOptions(const ServiceOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5694,6 +5907,11 @@ void ServiceOptions::SharedDtor() { } } +void ServiceOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceOptions_descriptor_; @@ -5724,13 +5942,14 @@ bool ServiceOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5759,15 +5978,9 @@ bool ServiceOptions::MergePartialFromCodedStream( void ServiceOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5819,7 +6032,9 @@ int ServiceOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5889,7 +6104,7 @@ const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MethodOptions::MethodOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5897,7 +6112,7 @@ void MethodOptions::InitAsDefaultInstance() { } MethodOptions::MethodOptions(const MethodOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5916,6 +6131,11 @@ void MethodOptions::SharedDtor() { } } +void MethodOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodOptions_descriptor_; @@ -5946,13 +6166,14 @@ bool MethodOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5981,15 +6202,9 @@ bool MethodOptions::MergePartialFromCodedStream( void MethodOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -6041,7 +6256,9 @@ int MethodOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6113,7 +6330,7 @@ const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER UninterpretedOption_NamePart::UninterpretedOption_NamePart() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -6121,7 +6338,7 @@ void UninterpretedOption_NamePart::InitAsDefaultInstance() { } UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6145,6 +6362,11 @@ void UninterpretedOption_NamePart::SharedDtor() { } } +void UninterpretedOption_NamePart::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_NamePart_descriptor_; @@ -6181,29 +6403,32 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // required string name_part = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name_part())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name_part())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name_part().data(), this->name_part().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_is_extension; break; } // required bool is_extension = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_is_extension: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &is_extension_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_is_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &is_extension_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -6226,12 +6451,6 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // required string name_part = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -6298,7 +6517,9 @@ int UninterpretedOption_NamePart::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6378,7 +6599,7 @@ const int UninterpretedOption::kStringValueFieldNumber; #endif // !_MSC_VER UninterpretedOption::UninterpretedOption() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -6386,7 +6607,7 @@ void UninterpretedOption::InitAsDefaultInstance() { } UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6416,6 +6637,11 @@ void UninterpretedOption::SharedDtor() { } } +void UninterpretedOption::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_descriptor_; @@ -6460,13 +6686,14 @@ bool UninterpretedOption::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_name())); + } else { goto handle_uninterpreted; } - parse_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_name())); if (input->ExpectTag(18)) goto parse_name; if (input->ExpectTag(26)) goto parse_identifier_value; break; @@ -6474,71 +6701,79 @@ bool UninterpretedOption::MergePartialFromCodedStream( // optional string identifier_value = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_identifier_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_identifier_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_identifier_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_identifier_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->identifier_value().data(), this->identifier_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(32)) goto parse_positive_int_value; break; } // optional uint64 positive_int_value = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_positive_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &positive_int_value_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_positive_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadUInt64( - input, &positive_int_value_)); - _set_bit(2); if (input->ExpectTag(40)) goto parse_negative_int_value; break; } // optional int64 negative_int_value = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_negative_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( + input, &negative_int_value_))); + _set_bit(3); + } else { goto handle_uninterpreted; } - parse_negative_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt64( - input, &negative_int_value_)); - _set_bit(3); if (input->ExpectTag(49)) goto parse_double_value; break; } // optional double double_value = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) { + parse_double_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>( + input, &double_value_))); + _set_bit(4); + } else { goto handle_uninterpreted; } - parse_double_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadDouble( - input, &double_value_)); - _set_bit(4); if (input->ExpectTag(58)) goto parse_string_value; break; } // optional bytes string_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_string_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_string_value())); + } else { goto handle_uninterpreted; } - parse_string_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_string_value())); if (input->ExpectAtEnd()) return true; break; } @@ -6561,15 +6796,9 @@ bool UninterpretedOption::MergePartialFromCodedStream( void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; for (int i = 0; i < this->name_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->name(i), output); } @@ -6708,7 +6937,9 @@ int UninterpretedOption::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6790,5 +7021,9 @@ void UninterpretedOption::Swap(UninterpretedOption* other) { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 4bf7369f..7df3ae16 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1,4 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto #ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED #define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED @@ -22,6 +23,7 @@ #include #include #include +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -73,6 +75,7 @@ enum FieldDescriptorProto_Type { 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; +const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { @@ -92,6 +95,7 @@ enum FieldDescriptorProto_Label { 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; +const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { @@ -111,6 +115,7 @@ enum FileOptions_OptimizeMode { 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_LITE_RUNTIME; +const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { @@ -123,12 +128,14 @@ inline bool FileOptions_OptimizeMode_Parse( FileOptions_OptimizeMode_descriptor(), name, value); } enum FieldOptions_CType { + FieldOptions_CType_STRING = 0, FieldOptions_CType_CORD = 1, FieldOptions_CType_STRING_PIECE = 2 }; LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); -const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD; +const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor(); inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { @@ -164,6 +171,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorSet& default_instance(); + void Swap(FileDescriptorSet* other); // implements Message ---------------------------------------------- @@ -186,7 +194,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -199,12 +207,15 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message inline int file_size() const; inline void clear_file(); static const int kFileFieldNumber = 1; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& file() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_file(); inline const ::google::protobuf::FileDescriptorProto& file(int index) const; inline ::google::protobuf::FileDescriptorProto* mutable_file(int index); inline ::google::protobuf::FileDescriptorProto* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_file(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -254,6 +265,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorProto& default_instance(); + void Swap(FileDescriptorProto* other); // implements Message ---------------------------------------------- @@ -276,7 +288,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -309,8 +321,6 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline int dependency_size() const; inline void clear_dependency(); static const int kDependencyFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); inline const ::std::string& dependency(int index) const; inline ::std::string* mutable_dependency(int index); inline void set_dependency(int index, const ::std::string& value); @@ -320,46 +330,56 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline void add_dependency(const ::std::string& value); inline void add_dependency(const char* value); inline void add_dependency(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); // repeated .google.protobuf.DescriptorProto message_type = 4; inline int message_type_size() const; inline void clear_message_type(); static const int kMessageTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& message_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type(); inline const ::google::protobuf::DescriptorProto& message_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_message_type(int index); inline ::google::protobuf::DescriptorProto* add_message_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_message_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int service_size() const; inline void clear_service(); static const int kServiceFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& service() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service(); inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const; inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); inline ::google::protobuf::ServiceDescriptorProto* add_service(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* + mutable_service(); // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 7; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // optional .google.protobuf.FileOptions options = 8; inline bool has_options() const; @@ -368,6 +388,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::FileOptions& options() const; inline ::google::protobuf::FileOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -426,6 +447,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto_ExtensionRange& default_instance(); + void Swap(DescriptorProto_ExtensionRange* other); // implements Message ---------------------------------------------- @@ -448,7 +470,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -471,6 +493,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto inline ::google::protobuf::int32 end() const; inline void set_end(::google::protobuf::int32 value); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -521,6 +544,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto& default_instance(); + void Swap(DescriptorProto* other); // implements Message ---------------------------------------------- @@ -543,7 +567,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -568,51 +592,61 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline int field_size() const; inline void clear_field(); static const int kFieldFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& field() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field(); inline const ::google::protobuf::FieldDescriptorProto& field(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index); inline ::google::protobuf::FieldDescriptorProto* add_field(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_field(); // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int nested_type_size() const; inline void clear_nested_type(); static const int kNestedTypeFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& nested_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type(); inline const ::google::protobuf::DescriptorProto& nested_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index); inline ::google::protobuf::DescriptorProto* add_nested_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_nested_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int extension_range_size() const; inline void clear_extension_range(); static const int kExtensionRangeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& extension_range() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range(); inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* + mutable_extension_range(); // optional .google.protobuf.MessageOptions options = 7; inline bool has_options() const; @@ -621,6 +655,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline const ::google::protobuf::MessageOptions& options() const; inline ::google::protobuf::MessageOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -677,6 +712,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa static const ::google::protobuf::Descriptor* descriptor(); static const FieldDescriptorProto& default_instance(); + void Swap(FieldDescriptorProto* other); // implements Message ---------------------------------------------- @@ -699,7 +735,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -732,6 +768,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Type_Type_MIN; static const Type Type_MAX = FieldDescriptorProto_Type_Type_MAX; + static const int Type_ARRAYSIZE = + FieldDescriptorProto_Type_Type_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Type_descriptor() { return FieldDescriptorProto_Type_descriptor(); @@ -755,6 +793,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Label_Label_MIN; static const Label Label_MAX = FieldDescriptorProto_Label_Label_MAX; + static const int Label_ARRAYSIZE = + FieldDescriptorProto_Label_Label_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Label_descriptor() { return FieldDescriptorProto_Label_descriptor(); @@ -837,6 +877,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::google::protobuf::FieldOptions& options() const; inline ::google::protobuf::FieldOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -897,6 +938,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const EnumDescriptorProto& default_instance(); + void Swap(EnumDescriptorProto* other); // implements Message ---------------------------------------------- @@ -919,7 +961,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -942,11 +984,13 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline int value_size() const; inline void clear_value(); static const int kValueFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& value() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value(); inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); inline ::google::protobuf::EnumValueDescriptorProto* add_value(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* + mutable_value(); // optional .google.protobuf.EnumOptions options = 3; inline bool has_options() const; @@ -955,6 +999,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::EnumOptions& options() const; inline ::google::protobuf::EnumOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1007,6 +1052,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueDescriptorProto& default_instance(); + void Swap(EnumValueDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1029,7 +1075,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1062,6 +1108,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline const ::google::protobuf::EnumValueOptions& options() const; inline ::google::protobuf::EnumValueOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1114,6 +1161,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes static const ::google::protobuf::Descriptor* descriptor(); static const ServiceDescriptorProto& default_instance(); + void Swap(ServiceDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1136,7 +1184,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1159,11 +1207,13 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline int method_size() const; inline void clear_method(); static const int kMethodFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& method() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method(); inline const ::google::protobuf::MethodDescriptorProto& method(int index) const; inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index); inline ::google::protobuf::MethodDescriptorProto* add_method(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* + mutable_method(); // optional .google.protobuf.ServiceOptions options = 3; inline bool has_options() const; @@ -1172,6 +1222,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline const ::google::protobuf::ServiceOptions& options() const; inline ::google::protobuf::ServiceOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1224,6 +1275,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess static const ::google::protobuf::Descriptor* descriptor(); static const MethodDescriptorProto& default_instance(); + void Swap(MethodDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1246,7 +1298,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1292,6 +1344,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::google::protobuf::MethodOptions& options() const; inline ::google::protobuf::MethodOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1347,6 +1400,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FileOptions& default_instance(); + void Swap(FileOptions* other); // implements Message ---------------------------------------------- @@ -1369,7 +1423,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1387,6 +1441,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { FileOptions_OptimizeMode_OptimizeMode_MIN; static const OptimizeMode OptimizeMode_MAX = FileOptions_OptimizeMode_OptimizeMode_MAX; + static const int OptimizeMode_ARRAYSIZE = + FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* OptimizeMode_descriptor() { return FileOptions_OptimizeMode_descriptor(); @@ -1435,17 +1491,41 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const; inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value); + // optional bool cc_generic_services = 16 [default = true]; + inline bool has_cc_generic_services() const; + inline void clear_cc_generic_services(); + static const int kCcGenericServicesFieldNumber = 16; + inline bool cc_generic_services() const; + inline void set_cc_generic_services(bool value); + + // optional bool java_generic_services = 17 [default = true]; + inline bool has_java_generic_services() const; + inline void clear_java_generic_services(); + static const int kJavaGenericServicesFieldNumber = 17; + inline bool java_generic_services() const; + inline void set_java_generic_services(bool value); + + // optional bool py_generic_services = 18 [default = true]; + inline bool has_py_generic_services() const; + inline void clear_py_generic_services(); + static const int kPyGenericServicesFieldNumber = 18; + inline bool py_generic_services() const; + inline void set_py_generic_services(bool value); + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1457,12 +1537,15 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::std::string _default_java_outer_classname_; bool java_multiple_files_; int optimize_for_; + bool cc_generic_services_; + bool java_generic_services_; + bool py_generic_services_; ::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_[(5 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1502,6 +1585,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MessageOptions& default_instance(); + void Swap(MessageOptions* other); // implements Message ---------------------------------------------- @@ -1524,7 +1608,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1551,13 +1635,16 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1610,6 +1697,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FieldOptions& default_instance(); + void Swap(FieldOptions* other); // implements Message ---------------------------------------------- @@ -1632,7 +1720,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1640,6 +1728,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FieldOptions_CType CType; + static const CType STRING = FieldOptions_CType_STRING; static const CType CORD = FieldOptions_CType_CORD; static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { @@ -1649,6 +1738,8 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { FieldOptions_CType_CType_MIN; static const CType CType_MAX = FieldOptions_CType_CType_MAX; + static const int CType_ARRAYSIZE = + FieldOptions_CType_CType_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* CType_descriptor() { return FieldOptions_CType_descriptor(); @@ -1663,7 +1754,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // accessors ------------------------------------------------------- - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool has_ctype() const; inline void clear_ctype(); static const int kCtypeFieldNumber = 1; @@ -1698,13 +1789,16 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1760,6 +1854,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumOptions& default_instance(); + void Swap(EnumOptions* other); // implements Message ---------------------------------------------- @@ -1782,7 +1877,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1795,13 +1890,16 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1852,6 +1950,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueOptions& default_instance(); + void Swap(EnumValueOptions* other); // implements Message ---------------------------------------------- @@ -1874,7 +1973,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1887,13 +1986,16 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1944,6 +2046,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const ServiceOptions& default_instance(); + void Swap(ServiceOptions* other); // implements Message ---------------------------------------------- @@ -1966,7 +2069,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1979,13 +2082,16 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2036,6 +2142,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MethodOptions& default_instance(); + void Swap(MethodOptions* other); // implements Message ---------------------------------------------- @@ -2058,7 +2165,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2071,13 +2178,16 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2128,6 +2238,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption_NamePart& default_instance(); + void Swap(UninterpretedOption_NamePart* other); // implements Message ---------------------------------------------- @@ -2150,7 +2261,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2176,6 +2287,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline bool is_extension() const; inline void set_is_extension(bool value); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2227,6 +2339,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption& default_instance(); + void Swap(UninterpretedOption* other); // implements Message ---------------------------------------------- @@ -2249,7 +2362,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2264,11 +2377,13 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline int name_size() const; inline void clear_name(); static const int kNameFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& name() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* mutable_name(); inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); inline ::google::protobuf::UninterpretedOption_NamePart* add_name(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* + mutable_name(); // optional string identifier_value = 3; inline bool has_identifier_value() const; @@ -2311,6 +2426,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline void set_string_value(const void* value, size_t size); inline ::std::string* mutable_string_value(); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2346,9 +2462,6 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag // =================================================================== -// =================================================================== - - // =================================================================== // FileDescriptorSet @@ -2360,14 +2473,6 @@ inline int FileDescriptorSet::file_size() const { inline void FileDescriptorSet::clear_file() { file_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -FileDescriptorSet::file() const { - return file_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* -FileDescriptorSet::mutable_file() { - return &file_; -} inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { return file_.Get(index); } @@ -2377,6 +2482,14 @@ inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file( inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { return file_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +FileDescriptorSet::mutable_file() { + return &file_; +} // ------------------------------------------------------------------- @@ -2473,14 +2586,6 @@ inline int FileDescriptorProto::dependency_size() const { inline void FileDescriptorProto::clear_dependency() { dependency_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -FileDescriptorProto::dependency() const { - return dependency_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -FileDescriptorProto::mutable_dependency() { - return &dependency_; -} inline const ::std::string& FileDescriptorProto::dependency(int index) const { return dependency_.Get(index); } @@ -2509,6 +2614,14 @@ inline void FileDescriptorProto::add_dependency(const char* value) { inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { dependency_.Add()->assign(reinterpret_cast(value), size); } +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +FileDescriptorProto::dependency() const { + return dependency_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +FileDescriptorProto::mutable_dependency() { + return &dependency_; +} // repeated .google.protobuf.DescriptorProto message_type = 4; inline int FileDescriptorProto::message_type_size() const { @@ -2517,14 +2630,6 @@ inline int FileDescriptorProto::message_type_size() const { inline void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -FileDescriptorProto::message_type() const { - return message_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -FileDescriptorProto::mutable_message_type() { - return &message_type_; -} inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { return message_type_.Get(index); } @@ -2534,6 +2639,14 @@ inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { return message_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + return message_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +FileDescriptorProto::mutable_message_type() { + return &message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int FileDescriptorProto::enum_type_size() const { @@ -2542,14 +2655,6 @@ inline int FileDescriptorProto::enum_type_size() const { inline void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -FileDescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -FileDescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2559,6 +2664,14 @@ inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enu inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +FileDescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int FileDescriptorProto::service_size() const { @@ -2567,14 +2680,6 @@ inline int FileDescriptorProto::service_size() const { inline void FileDescriptorProto::clear_service() { service_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& -FileDescriptorProto::service() const { - return service_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* -FileDescriptorProto::mutable_service() { - return &service_; -} inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { return service_.Get(index); } @@ -2584,6 +2689,14 @@ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { return service_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + return service_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +FileDescriptorProto::mutable_service() { + return &service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int FileDescriptorProto::extension_size() const { @@ -2592,14 +2705,6 @@ inline int FileDescriptorProto::extension_size() const { inline void FileDescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -FileDescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -FileDescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2609,6 +2714,14 @@ inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_ex inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +FileDescriptorProto::mutable_extension() { + return &extension_; +} // optional .google.protobuf.FileOptions options = 8; inline bool FileDescriptorProto::has_options() const { @@ -2716,14 +2829,6 @@ inline int DescriptorProto::field_size() const { inline void DescriptorProto::clear_field() { field_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::field() const { - return field_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_field() { - return &field_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { return field_.Get(index); } @@ -2733,6 +2838,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field( inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { return field_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + return field_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_field() { + return &field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int DescriptorProto::extension_size() const { @@ -2741,14 +2854,6 @@ inline int DescriptorProto::extension_size() const { inline void DescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2758,6 +2863,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extens inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_extension() { + return &extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int DescriptorProto::nested_type_size() const { @@ -2766,14 +2879,6 @@ inline int DescriptorProto::nested_type_size() const { inline void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -DescriptorProto::nested_type() const { - return nested_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -DescriptorProto::mutable_nested_type() { - return &nested_type_; -} inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { return nested_type_.Get(index); } @@ -2783,6 +2888,14 @@ inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { return nested_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + return nested_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +DescriptorProto::mutable_nested_type() { + return &nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int DescriptorProto::enum_type_size() const { @@ -2791,14 +2904,6 @@ inline int DescriptorProto::enum_type_size() const { inline void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -DescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -DescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2808,6 +2913,14 @@ inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_ty inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +DescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int DescriptorProto::extension_range_size() const { @@ -2816,14 +2929,6 @@ inline int DescriptorProto::extension_range_size() const { inline void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& -DescriptorProto::extension_range() const { - return extension_range_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* -DescriptorProto::mutable_extension_range() { - return &extension_range_; -} inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { return extension_range_.Get(index); } @@ -2833,6 +2938,14 @@ inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::muta inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { return extension_range_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + return extension_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +DescriptorProto::mutable_extension_range() { + return &extension_range_; +} // optional .google.protobuf.MessageOptions options = 7; inline bool DescriptorProto::has_options() const { @@ -3143,14 +3256,6 @@ inline int EnumDescriptorProto::value_size() const { inline void EnumDescriptorProto::clear_value() { value_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& -EnumDescriptorProto::value() const { - return value_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* -EnumDescriptorProto::mutable_value() { - return &value_; -} inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { return value_.Get(index); } @@ -3160,6 +3265,14 @@ inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutabl inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { return value_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + return value_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +EnumDescriptorProto::mutable_value() { + return &value_; +} // optional .google.protobuf.EnumOptions options = 3; inline bool EnumDescriptorProto::has_options() const { @@ -3310,14 +3423,6 @@ inline int ServiceDescriptorProto::method_size() const { inline void ServiceDescriptorProto::clear_method() { method_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& -ServiceDescriptorProto::method() const { - return method_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* -ServiceDescriptorProto::mutable_method() { - return &method_; -} inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { return method_.Get(index); } @@ -3327,6 +3432,14 @@ inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutabl inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { return method_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + return method_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +ServiceDescriptorProto::mutable_method() { + return &method_; +} // optional .google.protobuf.ServiceOptions options = 3; inline bool ServiceDescriptorProto::has_options() const { @@ -3613,6 +3726,54 @@ inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_Optimi optimize_for_ = value; } +// optional bool cc_generic_services = 16 [default = true]; +inline bool FileOptions::has_cc_generic_services() const { + return _has_bit(4); +} +inline void FileOptions::clear_cc_generic_services() { + cc_generic_services_ = true; + _clear_bit(4); +} +inline bool FileOptions::cc_generic_services() const { + return cc_generic_services_; +} +inline void FileOptions::set_cc_generic_services(bool value) { + _set_bit(4); + cc_generic_services_ = value; +} + +// optional bool java_generic_services = 17 [default = true]; +inline bool FileOptions::has_java_generic_services() const { + return _has_bit(5); +} +inline void FileOptions::clear_java_generic_services() { + java_generic_services_ = true; + _clear_bit(5); +} +inline bool FileOptions::java_generic_services() const { + return java_generic_services_; +} +inline void FileOptions::set_java_generic_services(bool value) { + _set_bit(5); + java_generic_services_ = value; +} + +// optional bool py_generic_services = 18 [default = true]; +inline bool FileOptions::has_py_generic_services() const { + return _has_bit(6); +} +inline void FileOptions::clear_py_generic_services() { + py_generic_services_ = true; + _clear_bit(6); +} +inline bool FileOptions::py_generic_services() const { + return py_generic_services_; +} +inline void FileOptions::set_py_generic_services(bool value) { + _set_bit(6); + py_generic_services_ = value; +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -3620,14 +3781,6 @@ inline int FileOptions::uninterpreted_option_size() const { inline void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FileOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FileOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3637,6 +3790,14 @@ inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FileOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3681,14 +3842,6 @@ inline int MessageOptions::uninterpreted_option_size() const { inline void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MessageOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MessageOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3698,17 +3851,25 @@ inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MessageOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- // FieldOptions -// optional .google.protobuf.FieldOptions.CType ctype = 1; +// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool FieldOptions::has_ctype() const { return _has_bit(0); } inline void FieldOptions::clear_ctype() { - ctype_ = 1; + ctype_ = 0; _clear_bit(0); } inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const { @@ -3801,14 +3962,6 @@ inline int FieldOptions::uninterpreted_option_size() const { inline void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FieldOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FieldOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3818,6 +3971,14 @@ inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpre inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FieldOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3830,14 +3991,6 @@ inline int EnumOptions::uninterpreted_option_size() const { inline void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3847,6 +4000,14 @@ inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3859,14 +4020,6 @@ inline int EnumValueOptions::uninterpreted_option_size() const { inline void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumValueOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumValueOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3876,6 +4029,14 @@ inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninte inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumValueOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3888,14 +4049,6 @@ inline int ServiceOptions::uninterpreted_option_size() const { inline void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -ServiceOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -ServiceOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3905,6 +4058,14 @@ inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +ServiceOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3917,14 +4078,6 @@ inline int MethodOptions::uninterpreted_option_size() const { inline void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MethodOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MethodOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3934,6 +4087,14 @@ inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpr inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MethodOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -4008,14 +4169,6 @@ inline int UninterpretedOption::name_size() const { inline void UninterpretedOption::clear_name() { name_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& -UninterpretedOption::name() const { - return name_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* -UninterpretedOption::mutable_name() { - return &name_; -} inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { return name_.Get(index); } @@ -4025,6 +4178,14 @@ inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mu inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { return name_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + return name_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +UninterpretedOption::mutable_name() { + return &name_; +} // optional string identifier_value = 3; inline bool UninterpretedOption::has_identifier_value() const { @@ -4159,6 +4320,8 @@ inline ::std::string* UninterpretedOption::mutable_string_value() { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google @@ -4187,4 +4350,6 @@ inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions } // namespace protobuf #endif // SWIG +// @@protoc_insertion_point(global_scope) + #endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 4db88a82..cc04aa8e 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -256,6 +256,22 @@ message FileOptions { + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. If you are + // using such a plugin, set these to false. In the future, we may change + // the default to false, so if you explicitly want generic services, you + // should explicitly set these to true. + optional bool cc_generic_services = 16 [default=true]; + optional bool java_generic_services = 17 [default=true]; + optional bool py_generic_services = 18 [default=true]; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -301,8 +317,11 @@ message FieldOptions { // representation of the field than it normally would. See the specific // options below. This option is not yet implemented in the open source // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1; + optional CType ctype = 1 [default = STRING]; enum CType { + // Default mode. + STRING = 0; + CORD = 1; STRING_PIECE = 2; @@ -313,6 +332,7 @@ message FieldOptions { // a single length-delimited blob. optional bool packed = 2; + // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc index 6ea674d1..95708d94 100644 --- a/src/google/protobuf/descriptor_database.cc +++ b/src/google/protobuf/descriptor_database.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -336,6 +337,35 @@ bool EncodedDescriptorDatabase::FindFileContainingSymbol( return MaybeParse(index_.FindSymbol(symbol_name), output); } +bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol( + const string& symbol_name, + string* output) { + pair encoded_file = index_.FindSymbol(symbol_name); + if (encoded_file.first == NULL) return false; + + // Optimization: The name should be the first field in the encoded message. + // Try to just read it directly. + io::CodedInputStream input(reinterpret_cast(encoded_file.first), + encoded_file.second); + + const uint32 kNameTag = internal::WireFormatLite::MakeTag( + FileDescriptorProto::kNameFieldNumber, + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + if (input.ReadTag() == kNameTag) { + // Success! + return internal::WireFormatLite::ReadString(&input, output); + } else { + // Slow path. Parse whole message. + FileDescriptorProto file_proto; + if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) { + return false; + } + *output = file_proto.name(); + return true; + } +} + bool EncodedDescriptorDatabase::FindFileContainingExtension( const string& containing_type, int field_number, diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h index c23ab75f..f32b1db9 100644 --- a/src/google/protobuf/descriptor_database.h +++ b/src/google/protobuf/descriptor_database.h @@ -280,6 +280,10 @@ class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { // need to keep it around. bool AddCopy(const void* encoded_file_descriptor, int size); + // Like FindFileContainingSymbol but returns only the name of the file. + bool FindNameOfFileContainingSymbol(const string& symbol_name, + string* output); + // implements DescriptorDatabase ----------------------------------- bool FindFileByName(const string& filename, FileDescriptorProto* output); diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index 33de1348..ac72ddcd 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -480,6 +480,40 @@ INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest, #endif // GTEST_HAS_PARAM_TEST +TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) { + // Create two files, one of which is in two parts. + FileDescriptorProto file1, file2a, file2b; + file1.set_name("foo.proto"); + file1.set_package("foo"); + file1.add_message_type()->set_name("Foo"); + file2a.set_name("bar.proto"); + file2b.set_package("bar"); + file2b.add_message_type()->set_name("Bar"); + + // Normal serialization allows our optimization to kick in. + string data1 = file1.SerializeAsString(); + + // Force out-of-order serialization to test slow path. + string data2 = file2b.SerializeAsString() + file2a.SerializeAsString(); + + // Create EncodedDescriptorDatabase containing both files. + EncodedDescriptorDatabase db; + db.Add(data1.data(), data1.size()); + db.Add(data2.data(), data2.size()); + + // Test! + string filename; + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename)); + EXPECT_EQ("bar.proto", filename); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename)); +} + // =================================================================== class MergedDescriptorDatabaseTest : public testing::Test { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 8fcfba3e..ec2c8152 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -3948,6 +3948,9 @@ TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) { EXPECT_EQ(0, call_counter.call_count_); } +// =================================================================== + + } // namespace descriptor_unittest } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index f8b5b4ea..c711a2da 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -106,7 +106,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField); case FD::CPPTYPE_STRING: - return sizeof(RepeatedPtrField); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(RepeatedPtrField); + } break; } } else { @@ -122,7 +126,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(Message*); case FD::CPPTYPE_STRING: - return sizeof(string*); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(string*); + } break; } } @@ -262,19 +270,24 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info) break; case FieldDescriptor::CPPTYPE_STRING: - if (!field->is_repeated()) { - if (is_prototype()) { - new(field_ptr) const string*(&field->default_value_string()); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + if (!field->is_repeated()) { + if (is_prototype()) { + new(field_ptr) const string*(&field->default_value_string()); + } else { + string* default_value = + *reinterpret_cast( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i])); + new(field_ptr) string*(default_value); + } } else { - string* default_value = - *reinterpret_cast( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i])); - new(field_ptr) string*(default_value); + new(field_ptr) RepeatedPtrField(); } - } else { - new(field_ptr) RepeatedPtrField(); - } + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: { @@ -329,8 +342,13 @@ DynamicMessage::~DynamicMessage() { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - reinterpret_cast*>(field_ptr) - ->~RepeatedPtrField(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + reinterpret_cast*>(field_ptr) + ->~RepeatedPtrField(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -340,10 +358,16 @@ DynamicMessage::~DynamicMessage() { } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - string* ptr = *reinterpret_cast(field_ptr); - if (ptr != &field->default_value_string()) { - delete ptr; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string* ptr = *reinterpret_cast(field_ptr); + if (ptr != &field->default_value_string()) { + delete ptr; + } + break; } + } } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) && !is_prototype()) { Message* message = *reinterpret_cast(field_ptr); @@ -373,7 +397,7 @@ void DynamicMessage::CrossLinkPrototypes() { // For singular fields, the field is just a pointer which should // point to the prototype. *reinterpret_cast(field_ptr) = - factory->GetPrototype(field->message_type()); + factory->GetPrototypeNoLock(field->message_type()); } } } @@ -410,11 +434,13 @@ struct DynamicMessageFactory::PrototypeMap { }; DynamicMessageFactory::DynamicMessageFactory() - : pool_(NULL), prototypes_(new PrototypeMap) { + : pool_(NULL), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool) - : pool_(pool), prototypes_(new PrototypeMap) { + : pool_(pool), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::~DynamicMessageFactory() { @@ -424,8 +450,18 @@ DynamicMessageFactory::~DynamicMessageFactory() { } } - const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) { + MutexLock lock(&prototypes_mutex_); + return GetPrototypeNoLock(type); +} + +const Message* DynamicMessageFactory::GetPrototypeNoLock( + const Descriptor* type) { + if (delegate_to_generated_factory_ && + type->file()->pool() == DescriptorPool::generated_pool()) { + return MessageFactory::generated_factory()->GetPrototype(type); + } + const DynamicMessage::TypeInfo** target = &prototypes_->map_[type]; if (*target != NULL) { // Already exists. diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index f38d3b09..81dd2c63 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -73,9 +73,25 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // Construct a DynamicMessageFactory that will search for extensions in // the given DescriptorPool. + // + // DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the + // parser to look for extensions in an alternate pool. However, note that + // this is almost never what you want to do. Almost all users should use + // the zero-arg constructor. DynamicMessageFactory(const DescriptorPool* pool); + ~DynamicMessageFactory(); + // Call this to tell the DynamicMessageFactory that if it is given a + // Descriptor d for which: + // d->file()->pool() == DescriptorPool::generated_pool(), + // then it should delegate to MessageFactory::generated_factory() instead + // of constructing a dynamic implementation of the message. In theory there + // is no down side to doing this, so it may become the default in the future. + void SetDelegateToGeneratedFactory(bool enable) { + delegate_to_generated_factory_ = enable; + } + // implements MessageFactory --------------------------------------- // Given a Descriptor, constructs the default (prototype) Message of that @@ -92,14 +108,12 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // The given descriptor must outlive the returned message, and hence must // outlive the DynamicMessageFactory. // - // Note that while GetPrototype() is idempotent, it is not const. This - // implies that it is not thread-safe to call GetPrototype() on the same - // DynamicMessageFactory in two different threads simultaneously. However, - // the returned objects are just as thread-safe as any other Message. + // The method is thread-safe. const Message* GetPrototype(const Descriptor* type); private: const DescriptorPool* pool_; + bool delegate_to_generated_factory_; // This struct just contains a hash_map. We can't #include from // this header due to hacks needed for hash_map portability in the open source @@ -108,6 +122,10 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // headers may only #include other public headers. struct PrototypeMap; scoped_ptr prototypes_; + mutable Mutex prototypes_mutex_; + + friend class DynamicMessage; + const Message* GetPrototypeNoLock(const Descriptor* type); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory); }; @@ -116,4 +134,3 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { } // namespace google #endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ - diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 4d5eb6cc..b1ffb0f5 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -59,24 +59,10 @@ inline WireFormatLite::CppType cpp_type(FieldType type) { } // Registry stuff. -struct ExtensionInfo { - inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) - : type(type), is_repeated(is_repeated), is_packed(is_packed) {} - - FieldType type; - bool is_repeated; - bool is_packed; - - union { - ExtensionSet::EnumValidityFunc* enum_is_valid; - const MessageLite* message_prototype; - }; -}; - typedef hash_map, ExtensionInfo> ExtensionRegistry; ExtensionRegistry* registry_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(registry_init_); +GoogleOnceType registry_init_; void DeleteRegistry() { delete registry_; @@ -110,6 +96,19 @@ const ExtensionInfo* FindRegisteredExtension( } // namespace +ExtensionFinder::~ExtensionFinder() {} + +bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) { + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type_, number); + if (extension == NULL) { + return false; + } else { + *output = *extension; + return true; + } +} + void ExtensionSet::RegisterExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed) { @@ -120,13 +119,18 @@ void ExtensionSet::RegisterExtension(const MessageLite* containing_type, Register(containing_type, number, info); } +static bool CallNoArgValidityFunc(const void* arg, int number) { + return reinterpret_cast(arg)(number); +} + void ExtensionSet::RegisterEnumExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed, EnumValidityFunc* is_valid) { GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM); ExtensionInfo info(type, is_repeated, is_packed); - info.enum_is_valid = is_valid; + info.enum_is_valid = CallNoArgValidityFunc; + info.enum_is_valid_arg = reinterpret_cast(is_valid); Register(containing_type, number, info); } @@ -211,9 +215,10 @@ LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ } \ \ void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ - LOWERCASE value) { \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = false; \ @@ -240,9 +245,10 @@ void ExtensionSet::SetRepeated##CAMELCASE( \ } \ \ void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ - bool packed, LOWERCASE value) { \ + bool packed, LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = true; \ @@ -279,9 +285,10 @@ int ExtensionSet::GetEnum(int number, int default_value) const { } } -void ExtensionSet::SetEnum(int number, FieldType type, int value) { +void ExtensionSet::SetEnum(int number, FieldType type, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = false; @@ -307,9 +314,10 @@ void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { } void ExtensionSet::AddEnum(int number, FieldType type, - bool packed, int value) { + bool packed, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = true; @@ -337,9 +345,10 @@ const string& ExtensionSet::GetString(int number, } } -string* ExtensionSet::MutableString(int number, FieldType type) { +string* ExtensionSet::MutableString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = false; @@ -365,9 +374,10 @@ string* ExtensionSet::MutableRepeatedString(int number, int index) { return iter->second.repeated_string_value->Mutable(index); } -string* ExtensionSet::AddString(int number, FieldType type) { +string* ExtensionSet::AddString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = true; @@ -400,9 +410,10 @@ const MessageLite& ExtensionSet::GetMessage( // MessageFactory* factory) const MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; @@ -435,9 +446,10 @@ MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) { } MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = true; @@ -563,7 +575,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { if (other_extension.is_repeated) { Extension* extension; - bool is_new = MaybeNewExtension(iter->first, &extension); + bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor, + &extension); if (is_new) { // Extension did not already exist in set. extension->type = other_extension.type; @@ -622,7 +635,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ case WireFormatLite::CPPTYPE_##UPPERCASE: \ Set##CAMELCASE(iter->first, other_extension.type, \ - other_extension.LOWERCASE##_value); \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ break; HANDLE_TYPE( INT32, int32, Int32); @@ -636,11 +650,13 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #undef HANDLE_TYPE case WireFormatLite::CPPTYPE_STRING: SetString(iter->first, other_extension.type, - *other_extension.string_value); + *other_extension.string_value, + other_extension.descriptor); break; case WireFormatLite::CPPTYPE_MESSAGE: MutableMessage(iter->first, other_extension.type, - *other_extension.message_value) + *other_extension.message_value, + other_extension.descriptor) ->CheckTypeAndMergeFrom(*other_extension.message_value); break; } @@ -678,64 +694,66 @@ bool ExtensionSet::IsInitialized() const { } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { int number = WireFormatLite::GetTagFieldNumber(tag); WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); - const ExtensionInfo* extension = - FindRegisteredExtension(containing_type, number); - + ExtensionInfo extension; bool is_unknown; - if (extension == NULL) { + if (!extension_finder->Find(number, &extension)) { is_unknown = true; - } else if (extension->is_packed) { + } else if (extension.is_packed) { is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); } else { WireFormatLite::WireType expected_wire_type = - WireFormatLite::WireTypeForFieldType(real_type(extension->type)); + WireFormatLite::WireTypeForFieldType(real_type(extension.type)); is_unknown = (wire_type != expected_wire_type); } if (is_unknown) { field_skipper->SkipField(input, tag); - } else if (extension->is_packed) { + } else if (extension.is_packed) { uint32 size; if (!input->ReadVarint32(&size)) return false; io::CodedInputStream::Limit limit = input->PushLimit(size); - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: \ while (input->BytesUntilLimit() > 0) { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - true, value); \ + true, value, extension.descriptor); \ } \ break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; - if (extension->enum_is_valid(value)) { - AddEnum(number, WireFormatLite::TYPE_ENUM, true, value); + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + if (extension.enum_is_valid(extension.enum_is_valid_arg, value)) { + AddEnum(number, WireFormatLite::TYPE_ENUM, true, value, + extension.descriptor); } } break; @@ -750,81 +768,89 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, input->PopLimit(limit); } else { - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ - if (extension->is_repeated) { \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ + if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - false, value); \ + false, value, extension.descriptor); \ } else { \ - Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value); \ + Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ + extension.descriptor); \ } \ } break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; - if (!extension->enum_is_valid(value)) { + if (!extension.enum_is_valid(extension.enum_is_valid_arg, value)) { // Invalid value. Treat as unknown. field_skipper->SkipUnknownEnum(number, value); - } else if (extension->is_repeated) { - AddEnum(number, WireFormatLite::TYPE_ENUM, false, value); + } else if (extension.is_repeated) { + AddEnum(number, WireFormatLite::TYPE_ENUM, false, value, + extension.descriptor); } else { - SetEnum(number, WireFormatLite::TYPE_ENUM, value); + SetEnum(number, WireFormatLite::TYPE_ENUM, value, + extension.descriptor); } break; } case WireFormatLite::TYPE_STRING: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadString(input, value)) return false; break; } case WireFormatLite::TYPE_BYTES: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadBytes(input, value)) return false; break; } case WireFormatLite::TYPE_GROUP: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadGroup(number, input, value)) return false; break; } case WireFormatLite::TYPE_MESSAGE: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadMessage(input, value)) return false; break; } @@ -837,7 +863,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseField(tag, input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -846,7 +873,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, // UnknownFieldSet* unknown_fields) bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { while (true) { uint32 tag = input->ReadTag(); @@ -854,12 +881,12 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, case 0: return true; case WireFormatLite::kMessageSetItemStartTag: - if (!ParseMessageSetItem(input, containing_type, field_skipper)) { + if (!ParseMessageSetItem(input, extension_finder, field_skipper)) { return false; } break; default: - if (!ParseField(tag, input, containing_type, field_skipper)) { + if (!ParseField(tag, input, extension_finder, field_skipper)) { return false; } break; @@ -870,7 +897,8 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseMessageSet(input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -879,7 +907,7 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, // UnknownFieldSet* unknown_fields); bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { // TODO(kenton): It would be nice to share code between this and // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the @@ -919,7 +947,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, reinterpret_cast(message_data.data()), message_data.size()); if (!ParseField(fake_tag, &sub_input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } message_data.clear(); @@ -939,7 +967,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, } else { // Already saw type_id, so we can parse this directly. if (!ParseField(fake_tag, input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } } @@ -969,26 +997,6 @@ void ExtensionSet::SerializeWithCachedSizes( } } -uint8* ExtensionSet::SerializeWithCachedSizesToArray( - int start_field_number, int end_field_number, - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeWithCachedSizes(start_field_number, - end_field_number, - &output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - void ExtensionSet::SerializeMessageSetWithCachedSizes( io::CodedOutputStream* output) const { map::const_iterator iter; @@ -997,23 +1005,6 @@ void ExtensionSet::SerializeMessageSetWithCachedSizes( } } -uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeMessageSetWithCachedSizes(&output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - int ExtensionSet::ByteSize() const { int total_size = 0; @@ -1039,10 +1030,13 @@ int ExtensionSet::MessageSetByteSize() const { // Defined in extension_set_heavy.cc. // int ExtensionSet::SpaceUsedExcludingSelf() const -bool ExtensionSet::MaybeNewExtension(int number, Extension** result) { +bool ExtensionSet::MaybeNewExtension(int number, + const FieldDescriptor* descriptor, + Extension** result) { pair::iterator, bool> insert_result = extensions_.insert(make_pair(number, Extension())); *result = &insert_result.first->second; + (*result)->descriptor = descriptor; return insert_result.second; } @@ -1206,20 +1200,20 @@ void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes( if (is_cleared) return; // Start group. - output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); + output->WriteTag(WireFormatLite::kMessageSetItemStartTag); // Write type ID. - output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); - output->WriteVarint32(number); - + WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, + number, + output); // Write message. - output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); - - output->WriteVarint32(message_value->GetCachedSize()); - message_value->SerializeWithCachedSizes(output); + WireFormatLite::WriteMessageMaybeToArray( + WireFormatLite::kMessageSetMessageNumber, + *message_value, + output); // End group. - output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); + output->WriteTag(WireFormatLite::kMessageSetItemEndTag); } int ExtensionSet::Extension::ByteSize(int number) const { diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index e5ac277e..b1a55338 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -53,6 +53,7 @@ namespace protobuf { class FieldDescriptor; // descriptor.h class DescriptorPool; // descriptor.h class MessageLite; // message_lite.h + class Message; // message.h class MessageFactory; // message.h class UnknownFieldSet; // unknown_field_set.h namespace io { @@ -76,6 +77,84 @@ namespace internal { // ExtensionSet::Extension small. typedef uint8 FieldType; +// A function which, given an integer value, returns true if the number +// matches one of the defined values for the corresponding enum type. This +// is used with RegisterEnumExtension, below. +typedef bool EnumValidityFunc(int number); + +// Version of the above which takes an argument. This is needed to deal with +// extensions that are not compiled in. +typedef bool EnumValidityFuncWithArg(const void* arg, int number); + +// Information about a registered extension. +struct ExtensionInfo { + inline ExtensionInfo() {} + inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) + : type(type), is_repeated(is_repeated), is_packed(is_packed), + descriptor(NULL) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + union { + struct { + EnumValidityFuncWithArg* enum_is_valid; + const void* enum_is_valid_arg; + }; + const MessageLite* message_prototype; + }; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; +}; + +// Abstract interface for an object which looks up extension definitions. Used +// when parsing. +class LIBPROTOBUF_EXPORT ExtensionFinder { + public: + virtual ~ExtensionFinder(); + + // Find the extension with the given containing type and number. + virtual bool Find(int number, ExtensionInfo* output) = 0; +}; + +// Implementation of ExtensionFinder which finds extensions defined in .proto +// files which have been compiled into the binary. +class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder { + public: + GeneratedExtensionFinder(const MessageLite* containing_type) + : containing_type_(containing_type) {} + virtual ~GeneratedExtensionFinder() {} + + // Returns true and fills in *output if found, otherwise returns false. + virtual bool Find(int number, ExtensionInfo* output); + + private: + const MessageLite* containing_type_; +}; + +// Implementation of ExtensionFinder which finds extensions in a given +// DescriptorPool, using the given MessageFactory to construct sub-objects. +// This class is implemented in extension_set_heavy.cc. +class LIBPROTOBUF_EXPORT DescriptorPoolExtensionFinder : public ExtensionFinder { + public: + DescriptorPoolExtensionFinder(const DescriptorPool* pool, + MessageFactory* factory, + const Descriptor* containing_type) + : pool_(pool), factory_(factory), containing_type_(containing_type) {} + virtual ~DescriptorPoolExtensionFinder() {} + + virtual bool Find(int number, ExtensionInfo* output); + + private: + const DescriptorPool* pool_; + MessageFactory* factory_; + const Descriptor* containing_type_; +}; + // This is an internal helper class intended for use within the protocol buffer // library and generated classes. Clients should not use it directly. Instead, // use the generated accessors such as GetExtension() of the class being @@ -92,11 +171,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet { ExtensionSet(); ~ExtensionSet(); - // A function which, given an integer value, returns true if the number - // matches one of the defined values for the corresponding enum type. This - // is used with RegisterEnumExtension, below. - typedef bool EnumValidityFunc(int number); - // These are called at startup by protocol-compiler-generated code to // register known extensions. The registrations are used by ParseField() // to look up extensions for parsed field numbers. Note that dynamic parsing @@ -117,11 +191,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // ================================================================= // Add all fields which are currently present to the given vector. This - // is useful to implement Reflection::ListFields(). The FieldDescriptors - // are looked up by number from the given pool. - // - // TODO(kenton): Looking up each field by number is somewhat unfortunate. - // Is there a better way? + // is useful to implement Reflection::ListFields(). void AppendToList(const Descriptor* containing_type, const DescriptorPool* pool, vector* output) const; @@ -176,21 +246,25 @@ class LIBPROTOBUF_EXPORT ExtensionSet { 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); - void SetUInt32(int number, FieldType type, uint32 value); - void SetUInt64(int number, FieldType type, uint64 value); - void SetFloat (int number, FieldType type, float value); - void SetDouble(int number, FieldType type, double value); - void SetBool (int number, FieldType type, bool value); - void SetEnum (int number, FieldType type, int value); - void SetString(int number, FieldType type, const string& value); - string * MutableString (int number, FieldType type); - MessageLite* MutableMessage(int number, FieldType type, - const MessageLite& prototype); + // |descriptor| may be NULL so long as it is known that the descriptor for + // the extension lives in the same pool as the descriptor for the containing + // type. +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void SetInt32 (int number, FieldType type, int32 value, desc); + void SetInt64 (int number, FieldType type, int64 value, desc); + void SetUInt32(int number, FieldType type, uint32 value, desc); + void SetUInt64(int number, FieldType type, uint64 value, desc); + void SetFloat (int number, FieldType type, float value, desc); + void SetDouble(int number, FieldType type, double value, desc); + void SetBool (int number, FieldType type, bool value, desc); + void SetEnum (int number, FieldType type, int value, desc); + void SetString(int number, FieldType type, const string& value, desc); + string * MutableString (int number, FieldType type, desc); MessageLite* MutableMessage(int number, FieldType type, - const Descriptor* message_type, + const MessageLite& prototype, desc); + MessageLite* MutableMessage(const FieldDescriptor* decsriptor, MessageFactory* factory); +#undef desc // repeated fields ------------------------------------------------- @@ -217,21 +291,22 @@ class LIBPROTOBUF_EXPORT ExtensionSet { string * MutableRepeatedString (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); - void AddUInt32(int number, FieldType type, bool packed, uint32 value); - void AddUInt64(int number, FieldType type, bool packed, uint64 value); - void AddFloat (int number, FieldType type, bool packed, float value); - void AddDouble(int number, FieldType type, bool packed, double value); - void AddBool (int number, FieldType type, bool packed, bool value); - 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); +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void AddInt32 (int number, FieldType type, bool packed, int32 value, desc); + void AddInt64 (int number, FieldType type, bool packed, int64 value, desc); + void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc); + void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc); + void AddFloat (int number, FieldType type, bool packed, float value, desc); + void AddDouble(int number, FieldType type, bool packed, double value, desc); + void AddBool (int number, FieldType type, bool packed, bool value, desc); + void AddEnum (int number, FieldType type, bool packed, int value, desc); + void AddString(int number, FieldType type, const string& value, desc); + string * AddString (int number, FieldType type, desc); MessageLite* AddMessage(int number, FieldType type, - const MessageLite& prototype); - MessageLite* AddMessage(int number, FieldType type, - const Descriptor* message_type, + const MessageLite& prototype, desc); + MessageLite* AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory); +#undef desc void RemoveLast(int number); void SwapElements(int number, int index1, int index2); @@ -257,7 +332,7 @@ 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 MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -265,13 +340,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type); bool ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* 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, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -279,7 +354,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type); bool ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields); // Write all extension fields with field numbers in the range @@ -359,6 +434,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // For repeated types, this indicates if the [packed=true] option is set. bool is_packed; + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; + // For packed fields, the size of the packed data is recorded here when // ByteSize() is called then used during serialization. // TODO(kenton): Use atomic when C++ supports it. @@ -368,9 +448,15 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void SerializeFieldWithCachedSizes( int number, io::CodedOutputStream* output) const; + uint8* SerializeFieldWithCachedSizesToArray( + int number, + uint8* target) const; void SerializeMessageSetItemWithCachedSizes( int number, io::CodedOutputStream* output) const; + uint8* SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const; int ByteSize(int number) const; int MessageSetItemByteSize(int number) const; void Clear(); @@ -381,14 +467,16 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // Gets the extension with the given number, creating it if it does not // already exist. Returns true if the extension did not already exist. - bool MaybeNewExtension(int number, Extension** result); + bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, + 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, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); + // Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This // friendship should automatically extend to ExtensionSet::Extension, but // unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this @@ -412,16 +500,18 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // These are just for convenience... inline void ExtensionSet::SetString(int number, FieldType type, - const string& value) { - MutableString(number, type)->assign(value); + const string& value, + const FieldDescriptor* descriptor) { + MutableString(number, type, descriptor)->assign(value); } inline void ExtensionSet::SetRepeatedString(int number, int index, const string& value) { MutableRepeatedString(number, index)->assign(value); } inline void ExtensionSet::AddString(int number, FieldType type, - const string& value) { - AddString(number, type)->assign(value); + const string& value, + const FieldDescriptor* descriptor) { + AddString(number, type, descriptor)->assign(value); } // =================================================================== @@ -502,7 +592,7 @@ template<> inline TYPE PrimitiveTypeTraits::Get( \ } \ template<> inline void PrimitiveTypeTraits::Set( \ int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ - set->Set##METHOD(number, field_type, value); \ + set->Set##METHOD(number, field_type, value, NULL); \ } \ \ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ @@ -516,7 +606,7 @@ template<> inline void RepeatedPrimitiveTypeTraits::Set( \ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ int number, FieldType field_type, bool is_packed, \ TYPE value, ExtensionSet* set) { \ - set->Add##METHOD(number, field_type, is_packed, value); \ + set->Add##METHOD(number, field_type, is_packed, value, NULL); \ } PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) @@ -544,11 +634,11 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { } static inline void Set(int number, FieldType field_type, const string& value, ExtensionSet* set) { - set->SetString(number, field_type, value); + set->SetString(number, field_type, value, NULL); } static inline string* Mutable(int number, FieldType field_type, ExtensionSet* set) { - return set->MutableString(number, field_type); + return set->MutableString(number, field_type, NULL); } }; @@ -571,11 +661,11 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { static inline void Add(int number, FieldType field_type, bool /*is_packed*/, const string& value, ExtensionSet* set) { - set->AddString(number, field_type, value); + set->AddString(number, field_type, value, NULL); } static inline string* Add(int number, FieldType field_type, ExtensionSet* set) { - return set->AddString(number, field_type); + return set->AddString(number, field_type, NULL); } }; @@ -596,7 +686,7 @@ class EnumTypeTraits { static inline void Set(int number, FieldType field_type, ConstType value, ExtensionSet* set) { GOOGLE_DCHECK(IsValid(value)); - set->SetEnum(number, field_type, value); + set->SetEnum(number, field_type, value, NULL); } }; @@ -616,7 +706,7 @@ class RepeatedEnumTypeTraits { static inline void Add(int number, FieldType field_type, bool is_packed, ConstType value, ExtensionSet* set) { GOOGLE_DCHECK(IsValid(value)); - set->AddEnum(number, field_type, is_packed, value); + set->AddEnum(number, field_type, is_packed, value, NULL); } }; @@ -640,7 +730,7 @@ class MessageTypeTraits { static inline MutableType Mutable(int number, FieldType field_type, ExtensionSet* set) { return static_cast( - set->MutableMessage(number, field_type, Type::default_instance())); + set->MutableMessage(number, field_type, Type::default_instance(), NULL)); } }; @@ -659,7 +749,7 @@ class RepeatedMessageTypeTraits { static inline MutableType Add(int number, FieldType field_type, ExtensionSet* set) { return static_cast( - set->AddMessage(number, field_type, Type::default_instance())); + set->AddMessage(number, field_type, Type::default_instance(), NULL)); } }; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 8555f6f8..426ec5f4 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -40,6 +40,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -58,12 +59,26 @@ void ExtensionSet::AppendToList(const Descriptor* containing_type, } if (has) { - output->push_back( - pool->FindExtensionByNumber(containing_type, iter->first)); + // TODO(kenton): Looking up each field by number is somewhat unfortunate. + // Is there a better way? The problem is that descriptors are lazily- + // initialized, so they might not even be constructed until + // AppendToList() is called. + + if (iter->second.descriptor == NULL) { + output->push_back(pool->FindExtensionByNumber( + containing_type, iter->first)); + } else { + output->push_back(iter->second.descriptor); + } } } } +inline FieldDescriptor::Type real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); + return static_cast(type); +} + inline FieldDescriptor::CppType cpp_type(FieldType type) { return FieldDescriptor::TypeToCppType( static_cast(type)); @@ -88,16 +103,16 @@ const MessageLite& ExtensionSet::GetMessage(int number, } } -MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_packed = false; - const MessageLite* prototype = factory->GetPrototype(message_type); + const MessageLite* prototype = + factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); extension->message_value = prototype->New(); } else { @@ -107,12 +122,11 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, return extension->message_value; } -MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = @@ -128,7 +142,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, if (result == NULL) { const MessageLite* prototype; if (extension->repeated_message_value->size() == 0) { - prototype = factory->GetPrototype(message_type); + prototype = factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); } else { prototype = &extension->repeated_message_value->Get(0); @@ -139,18 +153,64 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, return result; } +static bool ValidateEnumUsingDescriptor(const void* arg, int number) { + return reinterpret_cast(arg) + ->FindValueByNumber(number) != NULL; +} + +bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) { + const FieldDescriptor* extension = + pool_->FindExtensionByNumber(containing_type_, number); + if (extension == NULL) { + return false; + } else { + output->type = extension->type(); + output->is_repeated = extension->is_repeated(); + output->is_packed = extension->options().packed(); + output->descriptor = extension; + if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + output->message_prototype = + factory_->GetPrototype(extension->message_type()); + GOOGLE_CHECK(output->message_prototype != NULL) + << "Extension factory's GetPrototype() returned NULL for extension: " + << extension->full_name(); + } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + output->enum_is_valid = ValidateEnumUsingDescriptor; + output->enum_is_valid_arg = extension->enum_type(); + } + + return true; + } +} + bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseField(tag, input, containing_type, &skipper); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseField(tag, input, &finder, &skipper); + } } bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseMessageSet(input, containing_type, &skipper); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseMessageSet(input, &finder, &skipper); + } } int ExtensionSet::SpaceUsedExcludingSelf() const { @@ -175,7 +235,7 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { if (is_repeated) { switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ - case WireFormatLite::CPPTYPE_##UPPERCASE: \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ break @@ -189,8 +249,9 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { HANDLE_TYPE( BOOL, bool); HANDLE_TYPE( ENUM, enum); HANDLE_TYPE( STRING, string); +#undef HANDLE_TYPE - case WireFormatLite::CPPTYPE_MESSAGE: + case FieldDescriptor::CPPTYPE_MESSAGE: // repeated_message_value is actually a RepeatedPtrField, // but MessageLite has no SpaceUsed(), so we must directly call // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type @@ -201,11 +262,11 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { } } else { switch (cpp_type(type)) { - case WireFormatLite::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); break; - case WireFormatLite::CPPTYPE_MESSAGE: + case FieldDescriptor::CPPTYPE_MESSAGE: total_size += down_cast(message_value)->SpaceUsed(); break; default: @@ -216,6 +277,162 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { return total_size; } +// The Serialize*ToArray methods are only needed in the heavy library, as +// the lite library only generates SerializeWithCachedSizes. +uint8* ExtensionSet::SerializeWithCachedSizesToArray( + int start_field_number, int end_field_number, + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.lower_bound(start_field_number); + iter != extensions_.end() && iter->first < end_field_number; + ++iter) { + target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first, + target); + } + return target; +} + +uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { + target = iter->second.SerializeMessageSetItemWithCachedSizesToArray( + iter->first, target); + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray( + int number, uint8* target) const { + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return target; + + target = WireFormatLite::WriteTagToArray(number, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target); + target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##ToArray(number, \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + target = WireFormatLite::Write##CAMELCASE##ToArray( \ + number, VALUE, target); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but serialize it the normal way. + GOOGLE_LOG(WARNING) << "Invalid message set extension."; + return SerializeFieldWithCachedSizesToArray(number, target); + } + + if (is_cleared) return target; + + // Start group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemStartTag, target); + // Write type ID. + target = WireFormatLite::WriteUInt32ToArray( + WireFormatLite::kMessageSetTypeIdNumber, number, target); + // Write message. + target = WireFormatLite::WriteMessageToArray( + WireFormatLite::kMessageSetMessageNumber, *message_value, target); + // End group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemEndTag, target); + return target; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 327aee02..000f846c 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -35,10 +35,15 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include @@ -477,6 +482,160 @@ TEST(ExtensionSetTest, InvalidEnumDeath) { #endif // GTEST_HAS_DEATH_TEST +TEST(ExtensionSetTest, DynamicExtensions) { + // Test adding a dynamic extension to a compiled-in message object. + + FileDescriptorProto dynamic_proto; + dynamic_proto.set_name("dynamic_extensions_test.proto"); + dynamic_proto.add_dependency( + unittest::TestAllExtensions::descriptor()->file()->name()); + dynamic_proto.set_package("dynamic_extensions"); + + // Copy the fields and nested types from TestDynamicExtensions into our new + // proto, converting the fields into extensions. + const Descriptor* template_descriptor = + unittest::TestDynamicExtensions::descriptor(); + DescriptorProto template_descriptor_proto; + template_descriptor->CopyTo(&template_descriptor_proto); + dynamic_proto.mutable_message_type()->MergeFrom( + template_descriptor_proto.nested_type()); + dynamic_proto.mutable_enum_type()->MergeFrom( + template_descriptor_proto.enum_type()); + dynamic_proto.mutable_extension()->MergeFrom( + template_descriptor_proto.field()); + + // For each extension that we added... + for (int i = 0; i < dynamic_proto.extension_size(); i++) { + // Set its extendee to TestAllExtensions. + FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i); + extension->set_extendee( + unittest::TestAllExtensions::descriptor()->full_name()); + + // If the field refers to one of the types nested in TestDynamicExtensions, + // make it refer to the type in our dynamic proto instead. + string prefix = "." + template_descriptor->full_name() + "."; + if (extension->has_type_name()) { + string* type_name = extension->mutable_type_name(); + if (HasPrefixString(*type_name, prefix)) { + type_name->replace(0, prefix.size(), ".dynamic_extensions."); + } + } + } + + // Now build the file, using the generated pool as an underlay. + DescriptorPool dynamic_pool(DescriptorPool::generated_pool()); + const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto); + ASSERT_TRUE(file != NULL); + DynamicMessageFactory dynamic_factory(&dynamic_pool); + dynamic_factory.SetDelegateToGeneratedFactory(true); + + // Construct a message that we can parse with the extensions we defined. + // Since the extensions were based off of the fields of TestDynamicExtensions, + // we can use that message to create this test message. + string data; + { + unittest::TestDynamicExtensions message; + message.set_scalar_extension(123); + message.set_enum_extension(unittest::FOREIGN_BAR); + message.set_dynamic_enum_extension( + unittest::TestDynamicExtensions::DYNAMIC_BAZ); + message.mutable_message_extension()->set_c(456); + message.mutable_dynamic_message_extension()->set_dynamic_field(789); + message.add_repeated_extension("foo"); + message.add_repeated_extension("bar"); + message.add_packed_extension(12); + message.add_packed_extension(-34); + message.add_packed_extension(56); + message.add_packed_extension(-78); + + // Also add some unknown fields. + + // An unknown enum value (for a known field). + message.mutable_unknown_fields()->AddVarint( + unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber, + 12345); + // A regular unknown field. + message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown"); + + message.SerializeToString(&data); + } + + // Now we can parse this using our dynamic extension definitions... + unittest::TestAllExtensions message; + { + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(message.ParseFromCodedStream(&input)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + } + + // Can we print it? + EXPECT_EQ( + "[dynamic_extensions.scalar_extension]: 123\n" + "[dynamic_extensions.enum_extension]: FOREIGN_BAR\n" + "[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n" + "[dynamic_extensions.message_extension] {\n" + " c: 456\n" + "}\n" + "[dynamic_extensions.dynamic_message_extension] {\n" + " dynamic_field: 789\n" + "}\n" + "[dynamic_extensions.repeated_extension]: \"foo\"\n" + "[dynamic_extensions.repeated_extension]: \"bar\"\n" + "[dynamic_extensions.packed_extension]: 12\n" + "[dynamic_extensions.packed_extension]: -34\n" + "[dynamic_extensions.packed_extension]: 56\n" + "[dynamic_extensions.packed_extension]: -78\n" + "2002: 12345\n" + "54321: \"unknown\"\n", + message.DebugString()); + + // Can we serialize it? + // (Don't use EXPECT_EQ because we don't want to dump raw binary data to the + // terminal on failure.) + EXPECT_TRUE(message.SerializeAsString() == data); + + // What if we parse using the reflection-based parser? + { + unittest::TestAllExtensions message2; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + EXPECT_EQ(message.DebugString(), message2.DebugString()); + } + + // Are the embedded generated types actually using the generated objects? + { + const FieldDescriptor* message_extension = + file->FindExtensionByName("message_extension"); + ASSERT_TRUE(message_extension != NULL); + const Message& sub_message = + message.GetReflection()->GetMessage(message, message_extension); + const unittest::ForeignMessage* typed_sub_message = + dynamic_cast(&sub_message); + ASSERT_TRUE(typed_sub_message != NULL); + EXPECT_EQ(456, typed_sub_message->c()); + } + + // What does GetMessage() return for the embedded dynamic type if it isn't + // present? + { + const FieldDescriptor* dynamic_message_extension = + file->FindExtensionByName("dynamic_message_extension"); + ASSERT_TRUE(dynamic_message_extension != NULL); + const Message& parent = unittest::TestAllExtensions::default_instance(); + const Message& sub_message = + parent.GetReflection()->GetMessage(parent, dynamic_message_extension, + &dynamic_factory); + const Message* prototype = + dynamic_factory.GetPrototype(dynamic_message_extension->message_type()); + EXPECT_EQ(prototype, &sub_message); + } +} + } // namespace } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index e04b93cc..0f065ff2 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -239,8 +239,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - total_size += GetRaw >(message, field) - .SpaceUsedExcludingSelf(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + total_size += GetRaw >(message, field) + .SpaceUsedExcludingSelf(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -265,18 +270,24 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { break; case FieldDescriptor::CPPTYPE_STRING: { - const string* ptr = GetField(message, field); - - // Initially, the string points to the default value stored in - // the prototype. Only count the string if it has been changed - // from the default value. - const string* default_ptr = DefaultRaw(field); - - if (ptr != default_ptr) { - // string fields are represented by just a pointer, so also - // include sizeof(string) as well. - total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + const string* ptr = GetField(message, field); + + // Initially, the string points to the default value stored in + // the prototype. Only count the string if it has been changed + // from the default value. + const string* default_ptr = DefaultRaw(field); + + if (ptr != default_ptr) { + // string fields are represented by just a pointer, so also + // include sizeof(string) as well. + total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + } + break; } + } break; } @@ -376,8 +387,13 @@ void GeneratedMessageReflection::Swap( #undef SWAP_VALUES case FieldDescriptor::CPPTYPE_STRING: - std::swap(*MutableRaw(message1, field), - *MutableRaw(message2, field)); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + std::swap(*MutableRaw(message1, field), + *MutableRaw(message2, field)); + break; + } break; default: @@ -473,15 +489,20 @@ void GeneratedMessageReflection::ClearField( break; case FieldDescriptor::CPPTYPE_STRING: { - const string* default_ptr = DefaultRaw(field); - string** value = MutableRaw(message, field); - if (*value != default_ptr) { - if (field->has_default_value()) { - (*value)->assign(field->default_value_string()); - } else { - (*value)->clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + const string* default_ptr = DefaultRaw(field); + string** value = MutableRaw(message, field); + if (*value != default_ptr) { + if (field->has_default_value()) { + (*value)->assign(field->default_value_string()); + } else { + (*value)->clear(); + } } - } + break; + } break; } @@ -508,7 +529,12 @@ void GeneratedMessageReflection::ClearField( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: { - MutableRaw >(message, field)->Clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->Clear(); + break; + } break; } @@ -549,7 +575,12 @@ void GeneratedMessageReflection::RemoveLast( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - MutableRaw >(message, field)->RemoveLast(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->RemoveLast(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -658,7 +689,7 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ if (field->is_extension()) { \ return MutableExtensionSet(message)->Set##TYPENAME( \ - field->number(), field->type(), value); \ + field->number(), field->type(), value, field); \ } else { \ SetField(message, field, value); \ } \ @@ -694,7 +725,8 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ if (field->is_extension()) { \ MutableExtensionSet(message)->Add##TYPENAME( \ - field->number(), field->type(), field->options().packed(), value); \ + field->number(), field->type(), field->options().packed(), value, \ + field); \ } else { \ AddField(message, field, value); \ } \ @@ -718,7 +750,14 @@ string GeneratedMessageReflection::GetString( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -730,7 +769,14 @@ const string& GeneratedMessageReflection::GetStringReference( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -741,13 +787,19 @@ void GeneratedMessageReflection::SetString( USAGE_CHECK_ALL(SetString, SINGULAR, STRING); if (field->is_extension()) { return MutableExtensionSet(message)->SetString(field->number(), - field->type(), value); + field->type(), value, field); } else { - string** ptr = MutableField(message, field); - if (*ptr == DefaultRaw(field)) { - *ptr = new string(value); - } else { - (*ptr)->assign(value); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string** ptr = MutableField(message, field); + if (*ptr == DefaultRaw(field)) { + *ptr = new string(value); + } else { + (*ptr)->assign(value); + } + break; + } } } } @@ -759,7 +811,14 @@ string GeneratedMessageReflection::GetRepeatedString( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -770,7 +829,14 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -783,7 +849,12 @@ void GeneratedMessageReflection::SetRepeatedString( MutableExtensionSet(message)->SetRepeatedString( field->number(), index, value); } else { - *MutableRepeatedField(message, field, index) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *MutableRepeatedField(message, field, index) = value; + break; + } } } @@ -794,9 +865,14 @@ void GeneratedMessageReflection::AddString( USAGE_CHECK_ALL(AddString, REPEATED, STRING); if (field->is_extension()) { MutableExtensionSet(message)->AddString(field->number(), - field->type(), value); + field->type(), value, field); } else { - *AddField(message, field) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *AddField(message, field) = value; + break; + } } } @@ -828,7 +904,7 @@ void GeneratedMessageReflection::SetEnum( if (field->is_extension()) { MutableExtensionSet(message)->SetEnum(field->number(), field->type(), - value->number()); + value->number(), field); } else { SetField(message, field, value->number()); } @@ -874,7 +950,7 @@ void GeneratedMessageReflection::AddEnum( if (field->is_extension()) { MutableExtensionSet(message)->AddEnum(field->number(), field->type(), field->options().packed(), - value->number()); + value->number(), field); } else { AddField(message, field, value->number()); } @@ -883,14 +959,15 @@ void GeneratedMessageReflection::AddEnum( // ------------------------------------------------------------------- const Message& GeneratedMessageReflection::GetMessage( - const Message& message, const FieldDescriptor* field) const { + const Message& message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast( - GetExtensionSet(message).GetMessage(field->number(), - field->message_type(), - message_factory_)); + GetExtensionSet(message).GetMessage( + field->number(), field->message_type(), + factory == NULL ? message_factory_ : factory)); } else { const Message* result = GetRaw(message, field); if (result == NULL) { @@ -901,15 +978,14 @@ const Message& GeneratedMessageReflection::GetMessage( } Message* GeneratedMessageReflection::MutableMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast( - MutableExtensionSet(message)->MutableMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->MutableMessage(field, + factory == NULL ? message_factory_ : factory)); } else { Message** result = MutableField(message, field); if (*result == NULL) { @@ -948,15 +1024,15 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage( } Message* GeneratedMessageReflection::AddMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); + if (factory == NULL) factory = message_factory_; + if (field->is_extension()) { return static_cast( - MutableExtensionSet(message)->AddMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->AddMessage(field, factory)); } else { // We can't use AddField() because RepeatedPtrFieldBase doesn't // know how to allocate one. @@ -967,7 +1043,7 @@ Message* GeneratedMessageReflection::AddMessage( // We must allocate a new object. const Message* prototype; if (repeated->size() == 0) { - prototype = message_factory_->GetPrototype(field->message_type()); + prototype = factory->GetPrototype(field->message_type()); } else { prototype = &repeated->Get >(0); } @@ -1110,7 +1186,7 @@ inline Type* GeneratedMessageReflection::MutableField( } template -inline Type GeneratedMessageReflection::GetRepeatedField( +inline const Type& GeneratedMessageReflection::GetRepeatedField( const Message& message, const FieldDescriptor* field, int index) const { return GetRaw >(message, field).Get(index); } @@ -1138,7 +1214,7 @@ inline Type* GeneratedMessageReflection::MutableRepeatedField( template inline void GeneratedMessageReflection::AddField( - Message* message, const FieldDescriptor* field, Type value) const { + Message* message, const FieldDescriptor* field, const Type& value) const { MutableRaw >(message, field)->Add(value); } diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index d0b5b43b..b545fa1a 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -169,7 +169,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const EnumValueDescriptor* GetEnum(const Message& message, const FieldDescriptor* field) const; const Message& GetMessage(const Message& message, - const FieldDescriptor* field) const; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; void SetInt32 (Message* message, const FieldDescriptor* field, int32 value) const; @@ -190,7 +191,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const string& value) const; void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* MutableMessage(Message* message, const FieldDescriptor* field) const; + Message* MutableMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; int32 GetRepeatedInt32 (const Message& message, const FieldDescriptor* field, int index) const; @@ -262,7 +264,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { void AddEnum(Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* AddMessage(Message* message, const FieldDescriptor* field) const; + Message* AddMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; const FieldDescriptor* FindKnownExtensionByName(const string& name) const; const FieldDescriptor* FindKnownExtensionByNumber(int number) const; @@ -314,9 +317,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { inline Type* MutableField(Message* message, const FieldDescriptor* field) const; template - inline Type GetRepeatedField(const Message& message, - const FieldDescriptor* field, - int index) const; + inline const Type& GetRepeatedField(const Message& message, + const FieldDescriptor* field, + int index) const; template inline const Type& GetRepeatedPtrField(const Message& message, const FieldDescriptor* field, @@ -331,7 +334,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int index) const; template inline void AddField(Message* message, - const FieldDescriptor* field, Type value) const; + const FieldDescriptor* field, const Type& value) const; template inline Type* AddField(Message* message, const FieldDescriptor* field) const; diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index 9470bb08..7ac015d0 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -34,10 +34,19 @@ #include +#include + namespace google { namespace protobuf { namespace internal { +double Infinity() { + return std::numeric_limits::infinity(); +} +double NaN() { + return std::numeric_limits::quiet_NaN(); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 80dd028e..f306a2f1 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -42,22 +42,34 @@ namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + } +} + 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. +// with option 'deprecated=true' is used in the code, or for other things in +// generated code which are deprecated. // // 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 +# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED #else -# define DEPRECATED_PROTOBUF_FIELD +# define PROTOBUF_DEPRECATED #endif +// Constants for special floating point values. +double Infinity(); +double NaN(); + + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index e17a4775..6a91a13d 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -38,9 +38,9 @@ // will not cross the end of the buffer, since we can avoid a lot // of branching in this case. -#include +#include +#include #include -#include #include #include #include @@ -52,11 +52,6 @@ namespace io { namespace { -static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB - -static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB -static const int kDefaultRecursionLimit = 64; - static const int kMaxVarintBytes = 10; static const int kMaxVarint32Bytes = 5; @@ -65,72 +60,28 @@ static const int kMaxVarint32Bytes = 5; // CodedInputStream ================================================== -CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) - : input_(input), - buffer_(NULL), - buffer_size_(0), - total_bytes_read_(0), - overflow_bytes_(0), - last_tag_(0), - legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(INT_MAX), - buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), - total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), - recursion_limit_(kDefaultRecursionLimit) { - // 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_; + int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; if (backup_bytes > 0) { input_->BackUp(backup_bytes); // total_bytes_read_ doesn't include overflow_bytes_. - total_bytes_read_ -= buffer_size_ + buffer_size_after_limit_; - buffer_size_ = 0; + total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; + buffer_end_ = buffer_; buffer_size_after_limit_ = 0; overflow_bytes_ = 0; } } inline void CodedInputStream::RecomputeBufferLimits() { - buffer_size_ += buffer_size_after_limit_; + buffer_end_ += buffer_size_after_limit_; int closest_limit = min(current_limit_, total_bytes_limit_); if (closest_limit < total_bytes_read_) { // The limit position is in the current buffer. We must adjust // the buffer size accordingly. buffer_size_after_limit_ = total_bytes_read_ - closest_limit; - buffer_size_ -= buffer_size_after_limit_; + buffer_end_ -= buffer_size_after_limit_; } else { buffer_size_after_limit_ = 0; } @@ -139,7 +90,7 @@ inline void CodedInputStream::RecomputeBufferLimits() { CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // Current position relative to the beginning of the stream. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); Limit old_limit = current_limit_; @@ -176,7 +127,7 @@ void CodedInputStream::PopLimit(Limit limit) { int CodedInputStream::BytesUntilLimit() { if (current_limit_ == INT_MAX) return -1; int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); return current_limit_ - current_position; } @@ -186,7 +137,7 @@ void CodedInputStream::SetTotalBytesLimit( // Make sure the limit isn't already past, since this could confuse other // code. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); total_bytes_limit_ = max(current_position, total_bytes_limit); total_bytes_warning_threshold_ = warning_threshold; RecomputeBufferLimits(); @@ -203,7 +154,9 @@ void CodedInputStream::PrintTotalBytesLimitError() { bool CodedInputStream::Skip(int count) { if (count < 0) return false; // security: count is often user-supplied - if (count <= buffer_size_) { + const int original_buffer_size = BufferSize(); + + if (count <= original_buffer_size) { // Just skipping within the current buffer. Easy. Advance(count); return true; @@ -211,13 +164,13 @@ bool CodedInputStream::Skip(int count) { if (buffer_size_after_limit_ > 0) { // We hit a limit inside this buffer. Advance to the limit and fail. - Advance(buffer_size_); + Advance(original_buffer_size); return false; } - count -= buffer_size_; + count -= original_buffer_size; buffer_ = NULL; - buffer_size_ = 0; + buffer_end_ = buffer_; // Make sure this skip doesn't try to skip past the current limit. int closest_limit = min(current_limit_, total_bytes_limit_); @@ -236,20 +189,21 @@ bool CodedInputStream::Skip(int count) { } bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { - if (buffer_size_ == 0 && !Refresh()) return false; + if (BufferSize() == 0 && !Refresh()) return false; *data = buffer_; - *size = buffer_size_; + *size = BufferSize(); return true; } bool CodedInputStream::ReadRaw(void* buffer, int size) { - while (buffer_size_ < size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { // Reading past end of buffer. Copy what we have, then refresh. - memcpy(buffer, buffer_, buffer_size_); - buffer = reinterpret_cast(buffer) + buffer_size_; - size -= buffer_size_; - Advance(buffer_size_); + memcpy(buffer, buffer_, current_buffer_size); + buffer = reinterpret_cast(buffer) + current_buffer_size; + size -= current_buffer_size; + Advance(current_buffer_size); if (!Refresh()) return false; } @@ -261,27 +215,25 @@ bool CodedInputStream::ReadRaw(void* buffer, int size) { bool CodedInputStream::ReadString(string* buffer, int size) { if (size < 0) return false; // security: size is often user-supplied + return InternalReadStringInline(buffer, size); +} +bool CodedInputStream::ReadStringFallback(string* buffer, int size) { if (!buffer->empty()) { buffer->clear(); } - if (size < buffer_size_) { - STLStringResizeUninitialized(buffer, size); - memcpy((uint8*)buffer->data(), buffer_, size); - Advance(size); - return true; - } - - while (buffer_size_ < size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). - if (buffer_size_ != 0) { + if (current_buffer_size != 0) { // Note: string1.append(string2) is O(string2.size()) (as opposed to // O(string1.size() + string2.size()), which would be bad). - buffer->append(reinterpret_cast(buffer_), buffer_size_); + buffer->append(reinterpret_cast(buffer_), + current_buffer_size); } - size -= buffer_size_; - Advance(buffer_size_); + size -= current_buffer_size; + Advance(current_buffer_size); if (!Refresh()) return false; } @@ -292,11 +244,11 @@ bool CodedInputStream::ReadString(string* buffer, int size) { } -bool CodedInputStream::ReadLittleEndian32(uint32* value) { +bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -305,19 +257,15 @@ bool CodedInputStream::ReadLittleEndian32(uint32* value) { if (!ReadRaw(bytes, sizeof(*value))) return false; ptr = bytes; } - - *value = (static_cast(ptr[0]) ) | - (static_cast(ptr[1]) << 8) | - (static_cast(ptr[2]) << 16) | - (static_cast(ptr[3]) << 24); + ReadLittleEndian32FromArray(ptr, value); return true; } -bool CodedInputStream::ReadLittleEndian64(uint64* value) { +bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -326,99 +274,152 @@ bool CodedInputStream::ReadLittleEndian64(uint64* value) { if (!ReadRaw(bytes, sizeof(*value))) return false; ptr = bytes; } + ReadLittleEndian64FromArray(ptr, value); + return true; +} + +namespace { + +inline const uint8* ReadVarint32FromArray( + const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this read won't cross the end, so we can skip the checks. + const uint8* ptr = buffer; + uint32 b; + uint32 result; + + b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; + + // If the input is larger than 32 bits, we still need to read it all + // and discard the high-order bits. + for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { + b = *(ptr++); if (!(b & 0x80)) goto done; + } + + // We have overrun the maximum size of a varint (10 bytes). Assume + // the data is corrupt. + return NULL; + + done: + *value = result; + return ptr; +} + +} // namespace - uint32 part0 = (static_cast(ptr[0]) ) | - (static_cast(ptr[1]) << 8) | - (static_cast(ptr[2]) << 16) | - (static_cast(ptr[3]) << 24); - uint32 part1 = (static_cast(ptr[4]) ) | - (static_cast(ptr[5]) << 8) | - (static_cast(ptr[6]) << 16) | - (static_cast(ptr[7]) << 24); - *value = static_cast(part0) | - (static_cast(part1) << 32); +bool CodedInputStream::ReadVarint32Slow(uint32* value) { + uint64 result; + // Directly invoke ReadVarint64Fallback, since we already tried to optimize + // for one-byte varints. + if (!ReadVarint64Fallback(&result)) return false; + *value = (uint32)result; return true; } bool CodedInputStream::ReadVarint32Fallback(uint32* value) { - if (buffer_size_ >= kMaxVarintBytes || + if (BufferSize() >= kMaxVarintBytes || // Optimization: If the varint ends at exactly the end of the buffer, // we can detect that and still use the fast path. - (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this read won't cross the end, so we can skip the checks. - const uint8* ptr = buffer_; - uint32 b; - uint32 result; - - b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; - - // If the input is larger than 32 bits, we still need to read it all - // and discard the high-order bits. - for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { - b = *(ptr++); if (!(b & 0x80)) goto done; - } - - // We have overrun the maximum size of a varint (10 bytes). Assume - // the data is corrupt. - return false; - - done: - Advance(ptr - buffer_); - *value = result; + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + const uint8* end = ReadVarint32FromArray(buffer_, value); + if (end == NULL) return false; + buffer_ = end; return true; - } else { - // Optimization: If we're at a limit, detect that quickly. (This is - // common when reading tags.) - while (buffer_size_ == 0) { - // Detect cases where we definitely hit a byte limit without calling - // Refresh(). - if (// If we hit a limit, buffer_size_after_limit_ will be non-zero. - buffer_size_after_limit_ > 0 && - // Make sure that the limit we hit is not total_bytes_limit_, since - // in that case we still need to call Refresh() so that it prints an - // error. - total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { - // We hit a byte limit. - legitimate_message_end_ = true; - return false; - } + // Really slow case: we will incur the cost of an extra function call here, + // but moving this out of line reduces the size of this function, which + // improves the common case. In micro benchmarks, this is worth about 10-15% + return ReadVarint32Slow(value); + } +} - // Call refresh. - if (!Refresh()) { - // Refresh failed. Make sure that it failed due to EOF, not because - // we hit total_bytes_limit_, which, unlike normal limits, is not a - // valid place to end a message. - int current_position = total_bytes_read_ - buffer_size_after_limit_; - if (current_position >= total_bytes_limit_) { - // Hit total_bytes_limit_. But if we also hit the normal limit, - // we're still OK. - legitimate_message_end_ = current_limit_ == total_bytes_limit_; - } else { - legitimate_message_end_ = true; - } - return false; +uint32 CodedInputStream::ReadTagSlow() { + if (buffer_ == buffer_end_) { + // Call refresh. + if (!Refresh()) { + // Refresh failed. Make sure that it failed due to EOF, not because + // we hit total_bytes_limit_, which, unlike normal limits, is not a + // valid place to end a message. + int current_position = total_bytes_read_ - buffer_size_after_limit_; + if (current_position >= total_bytes_limit_) { + // Hit total_bytes_limit_. But if we also hit the normal limit, + // we're still OK. + legitimate_message_end_ = current_limit_ == total_bytes_limit_; + } else { + legitimate_message_end_ = true; } + return 0; } + } - // Slow path: Just do a 64-bit read. - uint64 result; - if (!ReadVarint64(&result)) return false; - *value = (uint32)result; - return true; + // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags + // again, since we have now refreshed the buffer. + uint64 result; + if (!ReadVarint64(&result)) return 0; + return static_cast(result); +} + +uint32 CodedInputStream::ReadTagFallback() { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + uint32 tag; + const uint8* end = ReadVarint32FromArray(buffer_, &tag); + if (end == NULL) { + return 0; + } + buffer_ = end; + return tag; + } else { + // We are commonly at a limit when attempting to read tags. Try to quickly + // detect this case without making another function call. + if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 && + // Make sure that the limit we hit is not total_bytes_limit_, since + // in that case we still need to call Refresh() so that it prints an + // error. + total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { + // We hit a byte limit. + legitimate_message_end_ = true; + return 0; + } + return ReadTagSlow(); } } -bool CodedInputStream::ReadVarint64(uint64* value) { - if (buffer_size_ >= kMaxVarintBytes || +bool CodedInputStream::ReadVarint64Slow(uint64* value) { + // Slow path: This read might cross the end of the buffer, so we + // need to check and refresh the buffer if and when it does. + + uint64 result = 0; + int count = 0; + uint32 b; + + do { + if (count == kMaxVarintBytes) return false; + while (buffer_ == buffer_end_) { + if (!Refresh()) return false; + } + b = *buffer_; + result |= static_cast(b & 0x7F) << (7 * count); + Advance(1); + ++count; + } while (b & 0x80); + + *value = result; + return true; +} + +bool CodedInputStream::ReadVarint64Fallback(uint64* value) { + if (BufferSize() >= kMaxVarintBytes || // Optimization: If the varint ends at exactly the end of the buffer, // we can detect that and still use the fast path. - (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) { + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { // Fast path: We have enough bytes left in the buffer to guarantee that // this read won't cross the end, so we can skip the checks. @@ -442,7 +443,7 @@ bool CodedInputStream::ReadVarint64(uint64* value) { // We have overrun the maximum size of a varint (10 bytes). The data // must be corrupt. - return false; + return NULL; done: Advance(ptr - buffer_); @@ -450,33 +451,13 @@ bool CodedInputStream::ReadVarint64(uint64* value) { (static_cast(part1) << 28) | (static_cast(part2) << 56); return true; - } else { - // Slow path: This read might cross the end of the buffer, so we - // need to check and refresh the buffer if and when it does. - - uint64 result = 0; - int count = 0; - uint32 b; - - do { - if (count == kMaxVarintBytes) return false; - while (buffer_size_ == 0) { - if (!Refresh()) return false; - } - b = *buffer_; - result |= static_cast(b & 0x7F) << (7 * count); - Advance(1); - ++count; - } while(b & 0x80); - - *value = result; - return true; + return ReadVarint64Slow(value); } } bool CodedInputStream::Refresh() { - GOOGLE_DCHECK_EQ(buffer_size_, 0); + GOOGLE_DCHECK_EQ(0, BufferSize()); if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || total_bytes_read_ == current_limit_) { @@ -507,25 +488,27 @@ bool CodedInputStream::Refresh() { } const void* void_buffer; - if (input_->Next(&void_buffer, &buffer_size_)) { + int buffer_size; + if (input_->Next(&void_buffer, &buffer_size)) { buffer_ = reinterpret_cast(void_buffer); - GOOGLE_CHECK_GE(buffer_size_, 0); + buffer_end_ = buffer_ + buffer_size; + GOOGLE_CHECK_GE(buffer_size, 0); - if (total_bytes_read_ <= INT_MAX - buffer_size_) { - total_bytes_read_ += buffer_size_; + if (total_bytes_read_ <= INT_MAX - buffer_size) { + total_bytes_read_ += buffer_size; } else { - // Overflow. Reset buffer_size_ to not include the bytes beyond INT_MAX. + // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX. // We can't get that far anyway, because total_bytes_limit_ is guaranteed // to be less than it. We need to keep track of the number of bytes // we discarded, though, so that we can call input_->BackUp() to back // up over them on destruction. // The following line is equivalent to: - // overflow_bytes_ = total_bytes_read_ + buffer_size_ - INT_MAX; + // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX; // except that it avoids overflows. Signed integer overflow has // undefined results according to the C standard. - overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size_); - buffer_size_ -= overflow_bytes_; + overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); + buffer_end_ -= overflow_bytes_; total_bytes_read_ = INT_MAX; } @@ -533,7 +516,7 @@ bool CodedInputStream::Refresh() { return true; } else { buffer_ = NULL; - buffer_size_ = 0; + buffer_end_ = NULL; return false; } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index fa023f35..dcbb0d45 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -114,10 +114,15 @@ #include #endif // !_MSC_VER #include +#include // for GOOGLE_PREDICT_TRUE macro namespace google { namespace protobuf { + +class DescriptorPool; +class MessageFactory; + namespace io { // Defined in this file. @@ -166,6 +171,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // types of data not covered by the CodedInputStream interface. bool GetDirectBufferPointer(const void** data, int* size); + // Like GetDirectBufferPointer, but this method is inlined, and does not + // attempt to Refresh() if the buffer is currently empty. + inline void GetDirectBufferPointerInline(const void** data, + int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); @@ -177,6 +187,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // could claim that a string is going to be MAX_INT bytes long in order to // crash the server because it can't allocate this much space at once. bool ReadString(string* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadStringInline(string* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; // Read a 32-bit little-endian integer. @@ -184,6 +198,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Read a 64-bit little-endian integer. bool ReadLittleEndian64(uint64* value); + // These methods read from an externally provided buffer. The caller is + // responsible for ensuring that the buffer has sufficient space. + // Read a 32-bit little-endian integer. + static const uint8* ReadLittleEndian32FromArray(const uint8* buffer, + uint32* value); + // Read a 64-bit little-endian integer. + static const uint8* ReadLittleEndian64FromArray(const uint8* buffer, + uint64* value); + // Read an unsigned integer with Varint encoding, truncating to 32 bits. // Reading a 32-bit value is equivalent to reading a 64-bit one and casting // it to uint32, but may be more efficient. @@ -208,6 +231,17 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // when given a constant parameter, but GCC doesn't want to inline by default. bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Like above, except this reads from the specified buffer. The caller is + // responsible for ensuring that the buffer is large enough to read a varint + // of the expected size. For best performance, use a compile-time constant as + // the expected tag parameter. + // + // Returns a pointer beyond the expected tag if it was found, or NULL if it + // was not. + static const uint8* ExpectTagFromArray( + const uint8* buffer, + uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Usually returns true if no more bytes can be read. Always returns false // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent // call to LastTagWas() will act as if ReadTag() had been called and returned @@ -318,12 +352,90 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Decrements the recursion depth. void DecrementRecursionDepth(); + // Extension Registry ---------------------------------------------- + // ADVANCED USAGE: 99.9% of people can ignore this section. + // + // By default, when parsing extensions, the parser looks for extension + // definitions in the pool which owns the outer message's Descriptor. + // However, you may call SetExtensionRegistry() to provide an alternative + // pool instead. This makes it possible, for example, to parse a message + // using a generated class, but represent some extensions using + // DynamicMessage. + + // Set the pool used to look up extensions. Most users do not need to call + // this as the correct pool will be chosen automatically. + // + // WARNING: It is very easy to misuse this. Carefully read the requirements + // below. Do not use this unless you are sure you need it. Almost no one + // does. + // + // Let's say you are parsing a message into message object m, and you want + // to take advantage of SetExtensionRegistry(). You must follow these + // requirements: + // + // The given DescriptorPool must contain m->GetDescriptor(). It is not + // sufficient for it to simply contain a descriptor that has the same name + // and content -- it must be the *exact object*. In other words: + // assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) == + // m->GetDescriptor()); + // There are two ways to satisfy this requirement: + // 1) Use m->GetDescriptor()->pool() as the pool. This is generally useless + // because this is the pool that would be used anyway if you didn't call + // SetExtensionRegistry() at all. + // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an + // "underlay". Read the documentation for DescriptorPool for more + // information about underlays. + // + // You must also provide a MessageFactory. This factory will be used to + // construct Message objects representing extensions. The factory's + // GetPrototype() MUST return non-NULL for any Descriptor which can be found + // through the provided pool. + // + // If the provided factory might return instances of protocol-compiler- + // generated (i.e. compiled-in) types, or if the outer message object m is + // a generated type, then the given factory MUST have this property: If + // GetPrototype() is given a Descriptor which resides in + // DescriptorPool::generated_pool(), the factory MUST return the same + // prototype which MessageFactory::generated_factory() would return. That + // is, given a descriptor for a generated type, the factory must return an + // instance of the generated class (NOT DynamicMessage). However, when + // given a descriptor for a type that is NOT in generated_pool, the factory + // is free to return any implementation. + // + // The reason for this requirement is that generated sub-objects may be + // accessed via the standard (non-reflection) extension accessor methods, + // and these methods will down-cast the object to the generated class type. + // If the object is not actually of that type, the results would be undefined. + // On the other hand, if an extension is not compiled in, then there is no + // way the code could end up accessing it via the standard accessors -- the + // only way to access the extension is via reflection. When using reflection, + // DynamicMessage and generated messages are indistinguishable, so it's fine + // if these objects are represented using DynamicMessage. + // + // Using DynamicMessageFactory on which you have called + // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the + // above requirement. + // + // If either pool or factory is NULL, both must be NULL. + // + // Note that this feature is ignored when parsing "lite" messages as they do + // not have descriptors. + void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory); + + // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool + // has been provided. + const DescriptorPool* GetExtensionPool(); + + // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no + // factory has been provided. + MessageFactory* GetExtensionFactory(); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); ZeroCopyInputStream* input_; const uint8* buffer_; - int buffer_size_; // size of current buffer + const uint8* buffer_end_; // pointer to the end of the buffer. int total_bytes_read_; // total bytes read from input_, including // the current buffer @@ -334,7 +446,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // LastTagWas() stuff. uint32 last_tag_; // result of last ReadTag(). - // This is set true by ReadVarint32Fallback() if it is called when exactly + // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly // at EOF, or by ExpectAtEnd() when it returns true. This happens when we // reach the end of a message and attempt to read another tag. bool legitimate_message_end_; @@ -365,6 +477,12 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Recursion depth limit, set by SetRecursionLimit(). int recursion_limit_; + // See SetExtensionRegistry(). + const DescriptorPool* extension_pool_; + MessageFactory* extension_factory_; + + // Private member functions. + // Advance the buffer by a given number of bytes. void Advance(int amount); @@ -379,10 +497,36 @@ class LIBPROTOBUF_EXPORT CodedInputStream { void PrintTotalBytesLimitError(); // Called when the buffer runs out to request more data. Implies an - // Advance(buffer_size_). + // Advance(BufferSize()). bool Refresh(); + // When parsing varints, we optimize for the common case of small values, and + // then optimize for the case when the varint fits within the current buffer + // piece. The Fallback method is used when we can't use the one-byte + // optimization. The Slow method is yet another fallback when the buffer is + // not large enough. Making the slow path out-of-line speeds up the common + // case by 10-15%. The slow path is fairly uncommon: it only triggers when a + // message crosses multiple buffers. bool ReadVarint32Fallback(uint32* value); + bool ReadVarint64Fallback(uint64* value); + bool ReadVarint32Slow(uint32* value); + bool ReadVarint64Slow(uint64* value); + bool ReadLittleEndian32Fallback(uint32* value); + bool ReadLittleEndian64Fallback(uint64* value); + // Fallback/slow methods for reading tags. These do not update last_tag_, + // but will set legitimate_message_end_ if we are at the end of the input + // stream. + uint32 ReadTagFallback(); + uint32 ReadTagSlow(); + bool ReadStringFallback(string* buffer, int size); + + // Return the size of the buffer. + int BufferSize() const; + + static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + + static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB + static const int kDefaultRecursionLimit = 64; }; // Class which encodes and writes binary data which is composed of varint- @@ -568,7 +712,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // methods optimize for that case. inline bool CodedInputStream::ReadVarint32(uint32* value) { - if (buffer_size_ != 0 && *buffer_ < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { *value = *buffer_; Advance(1); return true; @@ -577,20 +721,93 @@ inline bool CodedInputStream::ReadVarint32(uint32* value) { } } +inline bool CodedInputStream::ReadVarint64(uint64* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint64Fallback(value); + } +} + +// static +inline const uint8* CodedInputStream::ReadLittleEndian32FromArray( + const uint8* buffer, + uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + *value = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + return buffer + sizeof(*value); +#endif +} +// static +inline const uint8* CodedInputStream::ReadLittleEndian64FromArray( + const uint8* buffer, + uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + uint32 part0 = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + uint32 part1 = (static_cast(buffer[4]) ) | + (static_cast(buffer[5]) << 8) | + (static_cast(buffer[6]) << 16) | + (static_cast(buffer[7]) << 24); + *value = static_cast(part0) | + (static_cast(part1) << 32); + return buffer + sizeof(*value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian32(uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian32Fallback(value); + } +#else + return ReadLittleEndian32Fallback(value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian64Fallback(value); + } +#else + return ReadLittleEndian64Fallback(value); +#endif +} + inline uint32 CodedInputStream::ReadTag() { - if (buffer_size_ != 0 && buffer_[0] < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { last_tag_ = buffer_[0]; Advance(1); return last_tag_; - } else if (buffer_size_ >= 2 && buffer_[1] < 0x80) { - last_tag_ = (buffer_[0] & 0x7f) + (buffer_[1] << 7); - Advance(2); - return last_tag_; - } else if (ReadVarint32Fallback(&last_tag_)) { - return last_tag_; } else { - last_tag_ = 0; - return 0; + last_tag_ = ReadTagFallback(); + return last_tag_; } } @@ -604,14 +821,14 @@ inline bool CodedInputStream::ConsumedEntireMessage() { inline bool CodedInputStream::ExpectTag(uint32 expected) { if (expected < (1 << 7)) { - if (buffer_size_ != 0 && buffer_[0] == expected) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] == expected) { Advance(1); return true; } else { return false; } } else if (expected < (1 << 14)) { - if (buffer_size_ >= 2 && + if (GOOGLE_PREDICT_TRUE(BufferSize() >= 2) && buffer_[0] == static_cast(expected | 0x80) && buffer_[1] == static_cast(expected >> 7)) { Advance(2); @@ -625,11 +842,32 @@ inline bool CodedInputStream::ExpectTag(uint32 expected) { } } +inline const uint8* CodedInputStream::ExpectTagFromArray( + const uint8* buffer, uint32 expected) { + if (expected < (1 << 7)) { + if (buffer[0] == expected) { + return buffer + 1; + } + } else if (expected < (1 << 14)) { + if (buffer[0] == static_cast(expected | 0x80) && + buffer[1] == static_cast(expected >> 7)) { + return buffer + 2; + } + } + return NULL; +} + +inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, + int* size) { + *data = buffer_; + *size = buffer_end_ - buffer_; +} + inline bool CodedInputStream::ExpectAtEnd() { // If we are at a limit we know no more bytes can be read. Otherwise, it's // hard to say without calling Refresh(), and we'd rather not do that. - if (buffer_size_ == 0 && buffer_size_after_limit_ != 0) { + if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) { last_tag_ = 0; // Pretend we called ReadTag()... legitimate_message_end_ = true; // ... and it hit EOF. return true; @@ -677,11 +915,11 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else - target[0] = static_cast(value ); + target[0] = static_cast(value); target[1] = static_cast(value >> 8); target[2] = static_cast(value >> 16); target[3] = static_cast(value >> 24); @@ -691,18 +929,18 @@ inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else uint32 part0 = static_cast(value); uint32 part1 = static_cast(value >> 32); - target[0] = static_cast(part0 ); + target[0] = static_cast(part0); target[1] = static_cast(part0 >> 8); target[2] = static_cast(part0 >> 16); target[3] = static_cast(part0 >> 24); - target[4] = static_cast(part1 ); + target[4] = static_cast(part1); target[5] = static_cast(part1 >> 8); target[6] = static_cast(part1 >> 16); target[7] = static_cast(part1 >> 24); @@ -759,7 +997,6 @@ inline int CodedOutputStream::ByteCount() const { inline void CodedInputStream::Advance(int amount) { buffer_ += amount; - buffer_size_ -= amount; } inline void CodedOutputStream::Advance(int amount) { @@ -780,6 +1017,72 @@ inline void CodedInputStream::DecrementRecursionDepth() { if (recursion_depth_ > 0) --recursion_depth_; } +inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool, + MessageFactory* factory) { + extension_pool_ = pool; + extension_factory_ = factory; +} + +inline const DescriptorPool* CodedInputStream::GetExtensionPool() { + return extension_pool_; +} + +inline MessageFactory* CodedInputStream::GetExtensionFactory() { + return extension_factory_; +} + +inline int CodedInputStream::BufferSize() const { + return buffer_end_ - buffer_; +} + +inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) + : input_(input), + buffer_(NULL), + buffer_end_(NULL), + total_bytes_read_(0), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(INT_MAX), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); +} + +inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) + : input_(NULL), + buffer_(buffer), + buffer_end_(buffer + 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), + extension_pool_(NULL), + extension_factory_(NULL) { + // Note that setting current_limit_ == size is important to prevent some + // code paths from trying to access input_ and segfaulting. +} + +inline CodedInputStream::~CodedInputStream() { + if (input_ != NULL) { + BackUpInputToCurrentPosition(); + } +} + } // namespace io } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index e165fb93..7d298332 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -242,6 +242,24 @@ TEST_1D(CodedStreamTest, ExpectTag, kVarintCases) { } } +TEST_1D(CodedStreamTest, ExpectTagFromArray, kVarintCases) { + memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); + + const uint32 expected_value = static_cast(kVarintCases_case.value); + + // If the expectation succeeds, it should return a pointer past the tag. + if (kVarintCases_case.size <= 2) { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, + expected_value + 1)); + EXPECT_TRUE(buffer_ + kVarintCases_case.size == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } else { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } +} + TEST_2D(CodedStreamTest, ReadVarint64, kVarintCases, kBlockSizes) { memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case); @@ -529,10 +547,32 @@ TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) { EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64))); } +// Tests using the static methods to read fixed-size values from raw arrays. + +TEST_1D(CodedStreamTest, ReadLittleEndian32FromArray, kFixed32Cases) { + memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes)); + + uint32 value; + const uint8* end = CodedInputStream::ReadLittleEndian32FromArray( + buffer_, &value); + EXPECT_EQ(kFixed32Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + +TEST_1D(CodedStreamTest, ReadLittleEndian64FromArray, kFixed64Cases) { + memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes)); + + uint64 value; + const uint8* end = CodedInputStream::ReadLittleEndian64FromArray( + buffer_, &value); + EXPECT_EQ(kFixed64Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + // ------------------------------------------------------------------- // Raw reads and writes -const char kRawBytes[] = "Some bytes which will be writted and read raw."; +const char kRawBytes[] = "Some bytes which will be written and read raw."; TEST_1D(CodedStreamTest, ReadRaw, kBlockSizes) { memcpy(buffer_, kRawBytes, sizeof(kRawBytes)); @@ -593,6 +633,22 @@ TEST_1D(CodedStreamTest, ReadStringImpossiblyLarge, kBlockSizes) { } } +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) { + // Same test as above, except directly use a buffer. This used to cause + // crashes while the above did not. + uint8 buffer[8]; + CodedInputStream coded_input(buffer, 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) { + scoped_array buffer(new uint8[8]); + CodedInputStream coded_input(buffer.get(), 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + // ------------------------------------------------------------------- // Skip @@ -652,6 +708,36 @@ TEST_F(CodedStreamTest, GetDirectBufferPointerInput) { EXPECT_EQ(8, size); } +TEST_F(CodedStreamTest, GetDirectBufferPointerInlineInput) { + ArrayInputStream input(buffer_, sizeof(buffer_), 8); + CodedInputStream coded_input(&input); + + const void* ptr; + int size; + + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Peeking again should return the same pointer. + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Skip forward in the same buffer then peek again. + EXPECT_TRUE(coded_input.Skip(3)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 3, ptr); + EXPECT_EQ(5, size); + + // Skip to end of buffer and peek -- should return false and provide an empty + // buffer. It does not try to Refresh(). + EXPECT_TRUE(coded_input.Skip(5)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 8, ptr); + EXPECT_EQ(0, size); +} + TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) { ArrayOutputStream output(buffer_, sizeof(buffer_), 8); CodedOutputStream coded_output(&output); diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc index 84d277f4..e1a35ea2 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -315,6 +315,6 @@ bool GzipOutputStream::Close() { } // namespace io } // namespace protobuf -} // namespace google #endif // HAVE_ZLIB +} // namespace google diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 937d777e..c7d3074d 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -65,10 +65,10 @@ void Printer::Print(const map& variables, const char* text) { if (text[i] == '\n') { // Saw newline. If there is more text, we may need to insert an indent // here. So, write what we have so far, including the '\n'. - Write(text + pos, i - pos + 1); + WriteRaw(text + pos, i - pos + 1); pos = i + 1; - // Setting this true will cause the next Write() to insert an indent + // Setting this true will cause the next WriteRaw() to insert an indent // first. at_start_of_line_ = true; @@ -76,7 +76,7 @@ void Printer::Print(const map& variables, const char* text) { // Saw the start of a variable name. // Write what we have so far. - Write(text + pos, i - pos); + WriteRaw(text + pos, i - pos); pos = i + 1; // Find closing delimiter. @@ -90,14 +90,14 @@ void Printer::Print(const map& variables, const char* text) { string varname(text + pos, endpos - pos); if (varname.empty()) { // Two delimiters in a row reduce to a literal delimiter character. - Write(&variable_delimiter_, 1); + WriteRaw(&variable_delimiter_, 1); } else { // Replace with the variable's value. map::const_iterator iter = variables.find(varname); if (iter == variables.end()) { GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname; } else { - Write(iter->second.data(), iter->second.size()); + WriteRaw(iter->second.data(), iter->second.size()); } } @@ -108,7 +108,7 @@ void Printer::Print(const map& variables, const char* text) { } // Write the rest. - Write(text + pos, size - pos); + WriteRaw(text + pos, size - pos); } void Printer::Print(const char* text) { @@ -145,14 +145,23 @@ void Printer::Outdent() { indent_.resize(indent_.size() - 2); } -void Printer::Write(const char* data, int size) { +void Printer::PrintRaw(const string& data) { + WriteRaw(data.data(), data.size()); +} + +void Printer::PrintRaw(const char* data) { + if (failed_) return; + WriteRaw(data, strlen(data)); +} + +void Printer::WriteRaw(const char* data, int size) { if (failed_) return; if (size == 0) return; if (at_start_of_line_) { // Insert an indent. at_start_of_line_ = false; - Write(indent_.data(), indent_.size()); + WriteRaw(indent_.data(), indent_.size()); if (failed_) return; } diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index b7c4cf39..de085389 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -59,8 +59,8 @@ class ZeroCopyOutputStream; // zero_copy_stream.h // The above writes "My name is Bob." to the output stream. // // Printer aggressively enforces correct usage, crashing (with assert failures) -// in the case of undefined variables. This helps greatly in debugging code -// which uses it. This class is not intended to be used by production servers. +// in the case of undefined variables in debug builds. This helps greatly in +// debugging code which uses it. class LIBPROTOBUF_EXPORT Printer { public: // Create a printer that writes text to the given output stream. Use the @@ -94,15 +94,24 @@ class LIBPROTOBUF_EXPORT Printer { // level is zero. void Outdent(); + // Write a string to the output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const string& data); + + // Write a zero-delimited string to output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const char* data); + + // Write some bytes to the output buffer. + // This method does not look for newlines to add indentation. + void WriteRaw(const char* data, int size); + // True if any write to the underlying stream failed. (We don't just // crash in this case because this is an I/O failure, not a programming // error.) bool failed() const { return failed_; } private: - // Write some text to the output buffer. - void Write(const char* data, int size); - const char variable_delimiter_; ZeroCopyOutputStream* const output_; diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 69c7ee34..580a53da 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -76,10 +76,38 @@ TEST(Printer, BasicPrinting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World! This is the same line.\n" - "But this is a new one.\n" - "And this is another one."); + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one.", + buffer); + } +} + +TEST(Printer, WriteRaw) { + char buffer[8192]; + + for (int block_size = 1; block_size < 512; block_size *= 2) { + ArrayOutputStream output(buffer, sizeof(buffer), block_size); + + { + string string_obj = "From an object\n"; + Printer printer(&output, '$'); + printer.WriteRaw("Hello World!", 12); + printer.PrintRaw(" This is the same line.\n"); + printer.PrintRaw("But this is a new one.\nAnd this is another one."); + printer.WriteRaw("\n", 1); + printer.PrintRaw(string_obj); + EXPECT_FALSE(printer.failed()); + } + + buffer[output.ByteCount()] = '\0'; + + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one." + "\n" + "From an object\n", + buffer); } } @@ -98,6 +126,7 @@ TEST(Printer, VariableSubstitution) { vars["abcdefg"] = "1234"; printer.Print(vars, "Hello $foo$!\nbar = $bar$\n"); + printer.PrintRaw("RawBit\n"); printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$"); vars["foo"] = "blah"; @@ -108,12 +137,13 @@ TEST(Printer, VariableSubstitution) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "bar = $foo$\n" - "1234\n" - "A literal dollar sign: $\n" - "Now foo = blah."); + EXPECT_STREQ("Hello World!\n" + "bar = $foo$\n" + "RawBit\n" + "1234\n" + "A literal dollar sign: $\n" + "Now foo = blah.", + buffer); } } @@ -125,15 +155,17 @@ TEST(Printer, InlineVariableSubstitution) { { Printer printer(&output, '$'); printer.Print("Hello $foo$!\n", "foo", "World"); + printer.PrintRaw("RawBit\n"); printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two"); EXPECT_FALSE(printer.failed()); } buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "one two\n"); + EXPECT_STREQ("Hello World!\n" + "RawBit\n" + "one two\n", + buffer); } TEST(Printer, Indenting) { @@ -156,6 +188,8 @@ TEST(Printer, Indenting) { printer.Indent(); printer.Print(" And this is still the same line.\n" "But this is indented.\n"); + printer.PrintRaw("RawBit has indent at start\n"); + printer.PrintRaw("but not after a raw newline\n"); printer.Print(vars, "Note that a newline in a variable will break " "indenting, as we see$newline$here.\n"); printer.Indent(); @@ -169,16 +203,19 @@ TEST(Printer, Indenting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, + EXPECT_STREQ( "This is not indented.\n" " This is indented\n" " And so is this\n" "But this is not. And this is still the same line.\n" " But this is indented.\n" - " Note that a newline in a variable will break indenting, as we see\n" + " RawBit has indent at start\n" + "but not after a raw newline\n" + "Note that a newline in a variable will break indenting, as we see\n" "here.\n" " And this is double-indented\n" - "Back to normal."); + "Back to normal.", + buffer); } } diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 0bda451b..75cbfed5 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -119,7 +119,7 @@ namespace { CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\v'); -CHARACTER_CLASS(Unprintable, c < ' ' && c != '\0'); +CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0'); CHARACTER_CLASS(Digit, '0' <= c && c <= '9'); CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7'); diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 98386e0b..d115161f 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -63,6 +63,11 @@ class LIBPROTOBUF_EXPORT ErrorCollector { // 1 to each before printing them. virtual void AddError(int line, int column, const string& message) = 0; + // Indicates that there was a warning in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddWarning(int line, int column, const string& message) { } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); }; diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index eac1455d..3598e188 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -397,6 +397,12 @@ MultiTokenCase kMultiTokenCases[] = { { Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0 }, { Tokenizer::TYPE_END , "" , 1, 3 }, }}, + + // Bytes with the high-order bit set should not be seen as control characters. + { "\300", { + { Tokenizer::TYPE_SYMBOL, "\300", 0, 0 }, + { Tokenizer::TYPE_END , "" , 0, 1 }, + }}, }; TEST_2D(TokenizerTest, MultipleTokens, kMultiTokenCases, kBlockSizes) { diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h index 64e96cd4..9fedb005 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.h +++ b/src/google/protobuf/io/zero_copy_stream_impl.h @@ -133,10 +133,11 @@ class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream { // A ZeroCopyOutputStream which writes to a file descriptor. // -// FileInputStream is preferred over using an ofstream with OstreamOutputStream. -// The latter will introduce an extra layer of buffering, harming performance. -// Also, it's conceivable that FileInputStream could someday be enhanced -// to use zero-copy file descriptors on OSs which support them. +// FileOutputStream is preferred over using an ofstream with +// OstreamOutputStream. The latter will introduce an extra layer of buffering, +// harming performance. Also, it's conceivable that FileOutputStream could +// someday be enhanced to use zero-copy file descriptors on OSs which +// support them. class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream { public: // Creates a stream that writes to the given Unix file descriptor. diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index f919b7ac..8229ee6d 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -403,7 +403,8 @@ TEST_F(IoTest, CompressionOptions) { string golden; File::ReadFileToStringOrDie( - TestSourceDir() + "/google/protobuf/testdata/golden_message", &golden); + TestSourceDir() + "/google/protobuf/testdata/golden_message", + &golden); GzipOutputStream::Options options; string gzip_compressed = Compress(golden, options); diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 4e5b662c..d43507cd 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -212,7 +212,7 @@ class GeneratedMessageFactory : public MessageFactory { }; GeneratedMessageFactory* generated_message_factory_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); +GoogleOnceType generated_message_factory_once_init_; void ShutdownGeneratedMessageFactory() { delete generated_message_factory_; @@ -227,7 +227,7 @@ GeneratedMessageFactory::GeneratedMessageFactory() {} GeneratedMessageFactory::~GeneratedMessageFactory() {} GeneratedMessageFactory* GeneratedMessageFactory::singleton() { - GoogleOnceInit(&generated_message_factory_once_init_, + ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, &InitGeneratedMessageFactory); return generated_message_factory_; } diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 54b596d5..c0062f98 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -148,6 +148,7 @@ namespace protobuf { // Defined in this file. class Message; class Reflection; +class MessageFactory; // Defined in other files. class Descriptor; // descriptor.h @@ -238,13 +239,15 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // Reflection object's SpaceUsed() method. virtual int SpaceUsed() const; - // Debugging ------------------------------------------------------- + // Debugging & Testing---------------------------------------------- // Generates a human readable form of this message, useful for debugging // and other purposes. string DebugString() const; // Like DebugString(), but with less whitespace. string ShortDebugString() const; + // Like DebugString(), but do not escape UTF-8 byte sequences. + string Utf8DebugString() const; // Convenience function useful in GDB. Prints DebugString() to stdout. void PrintDebugString() const; @@ -327,6 +330,7 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // GetReflection() wrappers. virtual Metadata GetMetadata() const = 0; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); }; @@ -453,8 +457,10 @@ class LIBPROTOBUF_EXPORT Reflection { const FieldDescriptor* field) const = 0; virtual const EnumValueDescriptor* GetEnum( const Message& message, const FieldDescriptor* field) const = 0; + // See MutableMessage() for the meaning of the "factory" parameter. virtual const Message& GetMessage(const Message& message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Get a string value without copying, if possible. // @@ -499,9 +505,19 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; - // Get a mutable pointer to a field with a message type. + // Get a mutable pointer to a field with a message type. If a MessageFactory + // is provided, it will be used to construct instances of the sub-message; + // otherwise, the default factory is used. If the field is an extension that + // does not live in the same pool as the containing message's descriptor (e.g. + // it lives in an overlay pool), then a MessageFactory must be provided. + // If you have no idea what that meant, then you probably don't need to worry + // about it (don't provide a MessageFactory). WARNING: If the + // FieldDescriptor is for a compiled-in extension, then + // factory->GetPrototype(field->message_type() MUST return an instance of the + // compiled-in class for this type, NOT DynamicMessage. virtual Message* MutableMessage(Message* message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Repeated field getters ------------------------------------------ @@ -603,8 +619,10 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void AddEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; + // See MutableMessage() for comments on the "factory" parameter. virtual Message* AddMessage(Message* message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Extensions ------------------------------------------------------ diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index a53740ad..7c8f37dc 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -33,9 +33,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. - #include - +#include #include #include #include @@ -52,6 +51,24 @@ string MessageLite::InitializationErrorString() const { namespace { +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) { + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + string InitializationErrorMessage(const char* action, const MessageLite& message) { // Note: We want to avoid depending on strutil in the lite library, otherwise @@ -215,9 +232,29 @@ bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const { bool MessageLite::SerializePartialToCodedStream( io::CodedOutputStream* output) const { - ByteSize(); // Force size to be cached. - SerializeWithCachedSizes(output); - return !output->HadError(); + const int size = ByteSize(); // Force size to be cached. + uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size); + if (buffer != NULL) { + uint8* end = SerializeWithCachedSizesToArray(buffer); + if (end - buffer != size) { + ByteSizeConsistencyError(size, ByteSize(), end - buffer); + } + return true; + } else { + int original_byte_count = output->ByteCount(); + SerializeWithCachedSizes(output); + if (output->HadError()) { + return false; + } + int final_byte_count = output->ByteCount(); + + if (final_byte_count - original_byte_count != size) { + ByteSizeConsistencyError(size, ByteSize(), + final_byte_count - original_byte_count); + } + + return true; + } } bool MessageLite::SerializeToZeroCopyStream( @@ -243,7 +280,9 @@ bool MessageLite::AppendPartialToString(string* output) const { STLStringResizeUninitialized(output, old_size + byte_size); uint8* start = reinterpret_cast(string_as_array(output) + old_size); uint8* end = SerializeWithCachedSizesToArray(start); - GOOGLE_CHECK_EQ(end - start, byte_size); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } @@ -265,9 +304,11 @@ bool MessageLite::SerializeToArray(void* data, int size) const { bool MessageLite::SerializePartialToArray(void* data, int size) const { int byte_size = ByteSize(); if (size < byte_size) return false; - uint8* end = - SerializeWithCachedSizesToArray(reinterpret_cast(data)); - GOOGLE_CHECK_EQ(end, reinterpret_cast(data) + byte_size); + uint8* start = reinterpret_cast(data); + uint8* end = SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 3230c04c..f7beb110 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -39,6 +39,18 @@ namespace google { namespace protobuf { namespace internal { +void RepeatedPtrFieldBase::Reserve(int new_size) { + if (total_size_ >= new_size) return; + + void** old_elements = elements_; + total_size_ = max(total_size_ * 2, new_size); + elements_ = new void*[total_size_]; + memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); + if (old_elements != initial_space_) { + delete [] old_elements; + } +} + void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { void** swap_elements = elements_; int swap_current_size = current_size_; diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 1696e2a3..5954db55 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -51,8 +51,8 @@ #include #include - namespace google { + namespace protobuf { class Message; @@ -76,10 +76,11 @@ class RepeatedField { int size() const; - Element Get(int index) const; + const Element& Get(int index) const; Element* Mutable(int index); - void Set(int index, Element value); - void Add(Element value); + void Set(int index, const Element& value); + void Add(const Element& value); + Element* Add(); // Remove the last element in the array. // We don't provide a way to remove any element other than the last // because it invites inefficient use, such as O(n^2) filtering loops @@ -94,6 +95,13 @@ class RepeatedField { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + // Resize the RepeatedField to a new, smaller size. This is O(1). + void Truncate(int new_size); + + void AddAlreadyReserved(const Element& value); + Element* AddAlreadyReserved(); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element* mutable_data(); @@ -128,10 +136,19 @@ class RepeatedField { int total_size_; Element initial_space_[kInitialSize]; + + // Move the contents of |from| into |to|, possibly clobbering |from| in the + // process. For primitive types this is just a memcpy(), but it could be + // specialized for non-primitive types to, say, swap each element instead. + void MoveArray(Element to[], Element from[], int size); + + // Copy the elements of |from| into |to|. + void CopyArray(Element to[], const Element from[], int size); }; namespace internal { template class RepeatedPtrIterator; +template class RepeatedPtrOverPtrsIterator; } // namespace internal namespace internal { @@ -189,8 +206,11 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { void Reserve(int new_size); + int Capacity() const; + // Used for constructing iterators. void* const* raw_data() const; + void** raw_mutable_data() const; template typename TypeHandler::Type** mutable_data(); @@ -204,6 +224,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template int SpaceUsedExcludingSelf() const; + // Advanced memory management -------------------------------------- // Like Add(), but if there are no cleared objects to use, returns NULL. @@ -215,7 +236,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template typename TypeHandler::Type* ReleaseLast(); - int ClearedCount(); + int ClearedCount() const; template void AddCleared(typename TypeHandler::Type* value); template @@ -279,13 +300,14 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase { static void Merge(const string& from, string* to) { *to = from; } }; -class StringTypeHandler : public StringTypeHandlerBase { +class LIBPROTOBUF_EXPORT StringTypeHandler : public StringTypeHandlerBase { public: static int SpaceUsed(const string& value) { return sizeof(value) + StringSpaceUsedExcludingSelf(value); } }; + } // namespace internal // RepeatedPtrField is like RepeatedField, but used for repeated strings or @@ -311,6 +333,8 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element** mutable_data(); @@ -331,6 +355,12 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { iterator end(); const_iterator end() const; + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator pointer_iterator; + pointer_iterator pointer_begin(); + pointer_iterator pointer_end(); + // Returns (an estimate of) the number of bytes used by the repeated field, // excluding sizeof(*this). int SpaceUsedExcludingSelf() const; @@ -363,7 +393,7 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Get the number of cleared objects that are currently being kept // around for reuse. - int ClearedCount(); + int ClearedCount() const; // Add an element to the pool of cleared objects, passing ownership to // the RepeatedPtrField. The element must be cleared prior to calling // this method. @@ -373,16 +403,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Requires: ClearedCount() > 0 Element* ReleaseCleared(); - private: + protected: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only + // subclass it in one place as a hack for compatibility with proto1. The + // subclass needs to know about TypeHandler in order to call protected + // methods on RepeatedPtrFieldBase. class TypeHandler; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); - // prototype_ is used for RepeatedPtrField and - // RepeatedPtrField only (see constructor). - // TODO(kenton): Can we use some template magic to avoid wasting space on - // this field when it isn't used? - const Element* prototype_; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); }; // implementation ==================================================== @@ -406,9 +436,25 @@ inline int RepeatedField::size() const { return current_size_; } +template +inline int RepeatedField::Capacity() const { + return total_size_; +} + +template +inline void RepeatedField::AddAlreadyReserved(const Element& value) { + GOOGLE_DCHECK_LT(size(), Capacity()); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::AddAlreadyReserved() { + GOOGLE_DCHECK_LT(size(), Capacity()); + return &elements_[current_size_++]; +} template -inline Element RepeatedField::Get(int index) const { +inline const Element& RepeatedField::Get(int index) const { GOOGLE_DCHECK_LT(index, size()); return elements_[index]; } @@ -420,17 +466,23 @@ inline Element* RepeatedField::Mutable(int index) { } template -inline void RepeatedField::Set(int index, Element value) { +inline void RepeatedField::Set(int index, const Element& value) { GOOGLE_DCHECK_LT(index, size()); elements_[index] = value; } template -inline void RepeatedField::Add(Element value) { +inline void RepeatedField::Add(const Element& value) { if (current_size_ == total_size_) Reserve(total_size_ + 1); elements_[current_size_++] = value; } +template +inline Element* RepeatedField::Add() { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + return &elements_[current_size_++]; +} + template inline void RepeatedField::RemoveLast() { GOOGLE_DCHECK_GT(current_size_, 0); @@ -443,10 +495,9 @@ inline void RepeatedField::Clear() { } template -void RepeatedField::MergeFrom(const RepeatedField& other) { +inline void RepeatedField::MergeFrom(const RepeatedField& other) { Reserve(current_size_ + other.current_size_); - memcpy(elements_ + current_size_, other.elements_, - sizeof(Element) * other.current_size_); + CopyArray(elements_ + current_size_, other.elements_, other.current_size_); current_size_ += other.current_size_; } @@ -469,17 +520,17 @@ void RepeatedField::Swap(RepeatedField* other) { // We may not be using initial_space_ but it's not worth checking. Just // copy it anyway. Element swap_initial_space[kInitialSize]; - memcpy(swap_initial_space, initial_space_, sizeof(initial_space_)); + MoveArray(swap_initial_space, initial_space_, kInitialSize); elements_ = other->elements_; current_size_ = other->current_size_; total_size_ = other->total_size_; - memcpy(initial_space_, other->initial_space_, sizeof(initial_space_)); + MoveArray(initial_space_, other->initial_space_, kInitialSize); other->elements_ = swap_elements; other->current_size_ = swap_current_size; other->total_size_ = swap_total_size; - memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space)); + MoveArray(other->initial_space_, swap_initial_space, kInitialSize); if (elements_ == other->initial_space_) { elements_ = initial_space_; @@ -520,19 +571,40 @@ inline int RepeatedField::SpaceUsedExcludingSelf() const { return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0; } +// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant +// amount of code bloat. template -inline void RepeatedField::Reserve(int new_size) { +void RepeatedField::Reserve(int new_size) { if (total_size_ >= new_size) return; Element* old_elements = elements_; total_size_ = max(total_size_ * 2, new_size); elements_ = new Element[total_size_]; - memcpy(elements_, old_elements, current_size_ * sizeof(elements_[0])); + MoveArray(elements_, old_elements, current_size_); if (old_elements != initial_space_) { delete [] old_elements; } } +template +inline void RepeatedField::Truncate(int new_size) { + GOOGLE_DCHECK_LE(new_size, current_size_); + current_size_ = new_size; +} + +template +inline void RepeatedField::MoveArray( + Element to[], Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + +template +inline void RepeatedField::CopyArray( + Element to[], const Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + + // ------------------------------------------------------------------- namespace internal { @@ -600,17 +672,25 @@ void RepeatedPtrFieldBase::Clear() { } template -void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { Reserve(current_size_ + other.current_size_); for (int i = 0; i < other.current_size_; i++) { TypeHandler::Merge(other.Get(i), Add()); } } +inline int RepeatedPtrFieldBase::Capacity() const { + return total_size_; +} + inline void* const* RepeatedPtrFieldBase::raw_data() const { return elements_; } +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return elements_; +} + template inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this @@ -650,15 +730,29 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { } template -inline void RepeatedPtrFieldBase::AddAllocated( +void RepeatedPtrFieldBase::AddAllocated( typename TypeHandler::Type* value) { - if (allocated_size_ == total_size_) Reserve(total_size_ + 1); - // We don't care about the order of cleared elements, so if there's one - // in the way, just move it to the back of the array. - if (current_size_ < allocated_size_) { + // Make room for the new pointer. + if (current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++allocated_size_; + } else if (allocated_size_ == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast(elements_[current_size_])); + } else if (current_size_ < allocated_size_) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. elements_[allocated_size_] = elements_[current_size_]; + ++allocated_size_; + } else { + // There are no cleared objects. + ++allocated_size_; } - ++allocated_size_; + elements_[current_size_++] = value; } @@ -677,7 +771,7 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { } -inline int RepeatedPtrFieldBase::ClearedCount() { +inline int RepeatedPtrFieldBase::ClearedCount() const { return allocated_size_ - current_size_; } @@ -694,18 +788,6 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { return cast(elements_[--allocated_size_]); } -inline void RepeatedPtrFieldBase::Reserve(int new_size) { - if (total_size_ >= new_size) return; - - void** old_elements = elements_; - total_size_ = max(total_size_ * 2, new_size); - elements_ = new void*[total_size_]; - memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); - if (old_elements != initial_space_) { - delete [] old_elements; - } -} - } // namespace internal // ------------------------------------------------------------------- @@ -720,9 +802,7 @@ class RepeatedPtrField::TypeHandler template -inline RepeatedPtrField::RepeatedPtrField() - : prototype_(NULL) { -} +inline RepeatedPtrField::RepeatedPtrField() {} template RepeatedPtrField::~RepeatedPtrField() { @@ -802,7 +882,7 @@ inline Element* RepeatedPtrField::ReleaseLast() { template -inline int RepeatedPtrField::ClearedCount() { +inline int RepeatedPtrField::ClearedCount() const { return RepeatedPtrFieldBase::ClearedCount(); } @@ -821,6 +901,11 @@ inline void RepeatedPtrField::Reserve(int new_size) { return RepeatedPtrFieldBase::Reserve(new_size); } +template +inline int RepeatedPtrField::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + // ------------------------------------------------------------------- namespace internal { @@ -921,6 +1006,84 @@ class RepeatedPtrIterator void* const* it_; }; +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +template +class RepeatedPtrOverPtrsIterator + : public std::iterator { + public: + typedef RepeatedPtrOverPtrsIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element*> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrOverPtrsIterator() : it_(NULL) {} + explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void** it_; +}; + + } // namespace internal template @@ -944,6 +1107,18 @@ RepeatedPtrField::end() const { return iterator(raw_data() + size()); } +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} + + // Iterators and helper functions that follow the spirit of the STL // std::back_insert_iterator and std::back_inserter but are tailor-made // for RepeatedField and RepatedPtrField. Typical usage would be: diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 2d87ba88..798b05ee 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -37,6 +37,7 @@ #include #include +#include #include @@ -241,6 +242,29 @@ TEST(RepeatedField, MutableDataIsMutable) { EXPECT_EQ(2, field.Get(0)); } +TEST(RepeatedField, Truncate) { + RepeatedField field; + + field.Add(12); + field.Add(34); + field.Add(56); + field.Add(78); + EXPECT_EQ(4, field.size()); + + field.Truncate(3); + EXPECT_EQ(3, field.size()); + + field.Add(90); + EXPECT_EQ(4, field.size()); + EXPECT_EQ(90, field.Get(3)); + + // Truncations that don't change the size are allowed, but growing is not + // allowed. + field.Truncate(field.size()); + EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size"); +} + + // =================================================================== // RepeatedPtrField tests. These pretty much just mirror the RepeatedField // tests above. @@ -443,6 +467,52 @@ TEST(RepeatedPtrField, ClearedElements) { EXPECT_EQ(field.ClearedCount(), 0); } +// Test all code paths in AddAllocated(). +TEST(RepeatedPtrField, AddAlocated) { + RepeatedPtrField field; + while (field.size() < field.Capacity()) { + field.Add()->assign("filler"); + } + + int index = field.size(); + + // First branch: Field is at capacity with no cleared objects. + string* foo = new string("foo"); + field.AddAllocated(foo); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(foo, &field.Get(index)); + + // Last branch: Field is not at capacity and there are no cleared objects. + string* bar = new string("bar"); + field.AddAllocated(bar); + ++index; + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(bar, &field.Get(index)); + + // Third branch: Field is not at capacity and there are no cleared objects. + field.RemoveLast(); + string* baz = new string("baz"); + field.AddAllocated(baz); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(1, field.ClearedCount()); + EXPECT_EQ(baz, &field.Get(index)); + + // Second branch: Field is at capacity but has some cleared objects. + while (field.size() < field.Capacity()) { + field.Add()->assign("filler2"); + } + field.RemoveLast(); + index = field.size(); + string* qux = new string("qux"); + field.AddAllocated(qux); + EXPECT_EQ(index + 1, field.size()); + // We should have discarded the cleared object. + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(qux, &field.Get(index)); +} + TEST(RepeatedPtrField, MergeFrom) { RepeatedPtrField source, destination; @@ -614,6 +684,7 @@ TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) { string v = "f"; RepeatedPtrField::const_iterator it = lower_bound(proto_array_.begin(), proto_array_.end(), v); + EXPECT_EQ(*it, "n"); EXPECT_TRUE(it == proto_array_.begin() + 3); } @@ -624,6 +695,149 @@ TEST_F(RepeatedPtrFieldIteratorTest, Mutation) { EXPECT_EQ("qux", proto_array_.Get(0)); } +// ------------------------------------------------------------------- + +class RepeatedPtrFieldPtrsIteratorTest : public testing::Test { + protected: + virtual void SetUp() { + proto_array_.Add()->assign("foo"); + proto_array_.Add()->assign("bar"); + proto_array_.Add()->assign("baz"); + } + + RepeatedPtrField proto_array_; +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + EXPECT_EQ("foo", **iter); + ++iter; + EXPECT_EQ("bar", **(iter++)); + EXPECT_EQ("baz", **iter); + ++iter; + EXPECT_TRUE(proto_array_.pointer_end() == iter); + EXPECT_EQ("baz", **(--proto_array_.pointer_end())); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField::pointer_iterator iter2 = iter; + ++iter2; + ++iter2; + EXPECT_TRUE(iter + 2 == iter2); + EXPECT_TRUE(iter == iter2 - 2); + EXPECT_EQ("baz", *iter[2]); + EXPECT_EQ("baz", **(iter + 2)); + EXPECT_EQ(3, proto_array_.end() - proto_array_.begin()); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField::pointer_iterator iter2 = iter + 1; + EXPECT_TRUE(iter == iter); + EXPECT_TRUE(iter != iter2); + EXPECT_TRUE(iter < iter2); + EXPECT_TRUE(iter <= iter2); + EXPECT_TRUE(iter <= iter); + EXPECT_TRUE(iter2 > iter); + EXPECT_TRUE(iter2 >= iter); + EXPECT_TRUE(iter >= iter); +} + +// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs. +// Dereferencing an uninitialized iterator crashes the process. +TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) { + RepeatedPtrField::pointer_iterator iter; + EXPECT_TRUE(iter != proto_array_.pointer_begin()); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 1); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 2); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 3); + EXPECT_TRUE(iter != proto_array_.pointer_end()); +} + + +// This comparison functor is required by the tests for RepeatedPtrOverPtrs. +// They operate on strings and need to compare strings as strings in +// any stl algorithm, even though the iterator returns a pointer to a string +// - i.e. *iter has type string*. +struct StringLessThan { + bool operator()(const string* z, const string& y) { + return *z < y; + } + bool operator()(const string* z, const string* y) { + return *z < *y; + } +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) { + proto_array_.Clear(); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("x"); + proto_array_.Add()->assign("y"); + + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + string v = "f"; + RepeatedPtrField::pointer_iterator it = + lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(), + v, StringLessThan()); + + GOOGLE_CHECK(*it != NULL); + + EXPECT_EQ(**it, "n"); + EXPECT_TRUE(it == proto_array_.pointer_begin() + 3); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + **iter = "qux"; + EXPECT_EQ("qux", proto_array_.Get(0)); + + EXPECT_EQ("bar", proto_array_.Get(1)); + EXPECT_EQ("baz", proto_array_.Get(2)); + ++iter; + delete *iter; + *iter = new string("a"); + ++iter; + delete *iter; + *iter = new string("b"); + EXPECT_EQ("a", proto_array_.Get(1)); + EXPECT_EQ("b", proto_array_.Get(2)); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) { + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("y"); + proto_array_.Add()->assign("x"); + EXPECT_EQ("foo", proto_array_.Get(0)); + EXPECT_EQ("n", proto_array_.Get(5)); + EXPECT_EQ("x", proto_array_.Get(9)); + sort(proto_array_.pointer_begin(), + proto_array_.pointer_end(), + StringLessThan()); + EXPECT_EQ("a", proto_array_.Get(0)); + EXPECT_EQ("baz", proto_array_.Get(2)); + EXPECT_EQ("y", proto_array_.Get(9)); +} + + // ----------------------------------------------------------------------------- // Unit-tests for the insert iterators // google::protobuf::RepeatedFieldBackInserter, diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 3f002373..848ec3ab 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -171,7 +171,13 @@ static const int64 kint64min = -kint64max - 1; static const uint32 kuint32max = 0xFFFFFFFFu; static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); -#undef GOOGLE_ATTRIBUTE_ALWAYS_INLINE +// ------------------------------------------------------------------- +// Annotations: Some parts of the code have been annotated in ways that might +// be useful to some compilers or tools, but are not supported universally. +// You can #define these annotations yourself if the default implementation +// is not right for you. + +#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE #if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) // For functions we want to force inline. // Introduced in gcc 3.1. @@ -180,14 +186,35 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); // Other compilers will have to figure it out for themselves. #define GOOGLE_ATTRIBUTE_ALWAYS_INLINE #endif +#endif -#undef GOOGLE_ATTRIBUTE_DEPRECATED +#ifndef GOOGLE_ATTRIBUTE_DEPRECATED #ifdef __GNUC__ // If the method/variable/type is used anywhere, produce a warning. #define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) #else #define GOOGLE_ATTRIBUTE_DEPRECATED #endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE +#endif +#endif + +// Delimits a block of code which may write to memory which is simultaneously +// written by other threads, but which has been determined to be thread-safe +// (e.g. because it is an idempotent write). +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN +#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN() +#endif +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END +#define GOOGLE_SAFE_CONCURRENT_WRITES_END() +#endif // =================================================================== // from google3/base/basictypes.h diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index 76d9d21e..bb658ba8 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -425,8 +425,8 @@ string UnescapeCEscapeString(const string& src) { // // Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. // ---------------------------------------------------------------------- -static int CEscapeInternal(const char* src, int src_len, char* dest, - int dest_len, bool use_hex) { +int CEscapeInternal(const char* src, int src_len, char* dest, + int dest_len, bool use_hex, bool utf8_safe) { const char* src_end = src + src_len; int used = 0; bool last_hex_escape = false; // true if last output char was \xNN @@ -447,7 +447,9 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, // Note that if we emit \xNN and the src character after that is a hex // digit then that digit must be escaped too to prevent it being // interpreted as part of the character code by C. - if (!isprint(*src) || (last_hex_escape && isxdigit(*src))) { + if ((!utf8_safe || static_cast(*src) < 0x80) && + (!isprint(*src) || + (last_hex_escape && isxdigit(*src)))) { if (dest_len - used < 4) // need space for 4 letter escape return -1; sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"), @@ -469,7 +471,7 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, } int CEscapeString(const char* src, int src_len, char* dest, int dest_len) { - return CEscapeInternal(src, src_len, dest, dest_len, false); + return CEscapeInternal(src, src_len, dest, dest_len, false, false); } // ---------------------------------------------------------------------- @@ -486,11 +488,33 @@ string CEscape(const string& src) { const int dest_length = src.size() * 4 + 1; // Maximum possible expansion scoped_array dest(new char[dest_length]); const int len = CEscapeInternal(src.data(), src.size(), - dest.get(), dest_length, false); + dest.get(), dest_length, false, false); GOOGLE_DCHECK_GE(len, 0); return string(dest.get(), len); } +namespace strings { + +string Utf8SafeCEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, false, true); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +string CHexEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, true, false); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +} // namespace strings + // ---------------------------------------------------------------------- // strto32_adaptor() // strtou32_adaptor() diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index c04c1230..777694b7 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -265,6 +265,14 @@ LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len, // ---------------------------------------------------------------------- LIBPROTOBUF_EXPORT string CEscape(const string& src); +namespace strings { +// Like CEscape() but does not escape bytes with the upper bit set. +LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src); + +// Like CEscape() but uses hex (\x) escapes instead of octals. +LIBPROTOBUF_EXPORT string CHexEscape(const string& src); +} // namespace strings + // ---------------------------------------------------------------------- // strto32() // strtou32() diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 0637c0a5..af8b3909 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -229,11 +229,11 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) { message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_string_piece"), - 1, "424"); + 1, "524"); message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_cord"), - 1, "425"); + 1, "525"); #endif // !PROTOBUF_TEST_NO_DESCRIPTORS } @@ -692,6 +692,40 @@ void TestUtil::SetPackedFields(unittest::TestPackedTypes* message) { message->add_packed_enum (unittest::FOREIGN_BAZ); } +void TestUtil::SetUnpackedFields(unittest::TestUnpackedTypes* message) { + // The values applied here must match those of SetPackedFields. + + message->add_unpacked_int32 (601); + message->add_unpacked_int64 (602); + message->add_unpacked_uint32 (603); + message->add_unpacked_uint64 (604); + message->add_unpacked_sint32 (605); + message->add_unpacked_sint64 (606); + message->add_unpacked_fixed32 (607); + message->add_unpacked_fixed64 (608); + message->add_unpacked_sfixed32(609); + message->add_unpacked_sfixed64(610); + message->add_unpacked_float (611); + message->add_unpacked_double (612); + message->add_unpacked_bool (true); + message->add_unpacked_enum (unittest::FOREIGN_BAR); + // add a second one of each field + message->add_unpacked_int32 (701); + message->add_unpacked_int64 (702); + message->add_unpacked_uint32 (703); + message->add_unpacked_uint64 (704); + message->add_unpacked_sint32 (705); + message->add_unpacked_sint64 (706); + message->add_unpacked_fixed32 (707); + message->add_unpacked_fixed64 (708); + message->add_unpacked_sfixed32(709); + message->add_unpacked_sfixed64(710); + message->add_unpacked_float (711); + message->add_unpacked_double (712); + message->add_unpacked_bool (false); + message->add_unpacked_enum (unittest::FOREIGN_BAZ); +} + // ------------------------------------------------------------------- void TestUtil::ModifyPackedFields(unittest::TestPackedTypes* message) { @@ -760,6 +794,56 @@ void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) { EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1)); } +void TestUtil::ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message) { + // The values expected here must match those of ExpectPackedFieldsSet. + + ASSERT_EQ(2, message.unpacked_int32_size ()); + ASSERT_EQ(2, message.unpacked_int64_size ()); + ASSERT_EQ(2, message.unpacked_uint32_size ()); + ASSERT_EQ(2, message.unpacked_uint64_size ()); + ASSERT_EQ(2, message.unpacked_sint32_size ()); + ASSERT_EQ(2, message.unpacked_sint64_size ()); + ASSERT_EQ(2, message.unpacked_fixed32_size ()); + ASSERT_EQ(2, message.unpacked_fixed64_size ()); + ASSERT_EQ(2, message.unpacked_sfixed32_size()); + ASSERT_EQ(2, message.unpacked_sfixed64_size()); + ASSERT_EQ(2, message.unpacked_float_size ()); + ASSERT_EQ(2, message.unpacked_double_size ()); + ASSERT_EQ(2, message.unpacked_bool_size ()); + ASSERT_EQ(2, message.unpacked_enum_size ()); + + EXPECT_EQ(601 , message.unpacked_int32 (0)); + EXPECT_EQ(602 , message.unpacked_int64 (0)); + EXPECT_EQ(603 , message.unpacked_uint32 (0)); + EXPECT_EQ(604 , message.unpacked_uint64 (0)); + EXPECT_EQ(605 , message.unpacked_sint32 (0)); + EXPECT_EQ(606 , message.unpacked_sint64 (0)); + EXPECT_EQ(607 , message.unpacked_fixed32 (0)); + EXPECT_EQ(608 , message.unpacked_fixed64 (0)); + EXPECT_EQ(609 , message.unpacked_sfixed32(0)); + EXPECT_EQ(610 , message.unpacked_sfixed64(0)); + EXPECT_EQ(611 , message.unpacked_float (0)); + EXPECT_EQ(612 , message.unpacked_double (0)); + EXPECT_EQ(true , message.unpacked_bool (0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.unpacked_enum(0)); + + EXPECT_EQ(701 , message.unpacked_int32 (1)); + EXPECT_EQ(702 , message.unpacked_int64 (1)); + EXPECT_EQ(703 , message.unpacked_uint32 (1)); + EXPECT_EQ(704 , message.unpacked_uint64 (1)); + EXPECT_EQ(705 , message.unpacked_sint32 (1)); + EXPECT_EQ(706 , message.unpacked_sint64 (1)); + EXPECT_EQ(707 , message.unpacked_fixed32 (1)); + EXPECT_EQ(708 , message.unpacked_fixed64 (1)); + EXPECT_EQ(709 , message.unpacked_sfixed32(1)); + EXPECT_EQ(710 , message.unpacked_sfixed64(1)); + EXPECT_EQ(711 , message.unpacked_float (1)); + EXPECT_EQ(712 , message.unpacked_double (1)); + EXPECT_EQ(false, message.unpacked_bool (1)); + EXPECT_EQ(unittest::FOREIGN_BAZ, message.unpacked_enum(1)); +} + // ------------------------------------------------------------------- void TestUtil::ExpectPackedClear( diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index 5a6ec88f..25165f3a 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -54,6 +54,7 @@ class TestUtil { static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message); static void SetPackedFields(unittest::TestPackedTypes* message); static void SetPackedExtensions(unittest::TestPackedExtensions* message); + static void SetUnpackedFields(unittest::TestUnpackedTypes* message); // Use the repeated versions of the set_*() accessors to modify all the // repeated fields of the messsage (which should already have been @@ -72,6 +73,8 @@ class TestUtil { static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message); static void ExpectPackedExtensionsSet( const unittest::TestPackedExtensions& message); + static void ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message); // Expect that the message is modified as would be expected from // Modify*Fields(). diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc index f813e8ee..e224781d 100644 --- a/src/google/protobuf/testing/file.cc +++ b/src/google/protobuf/testing/file.cc @@ -84,10 +84,13 @@ void File::ReadFileToStringOrDie(const string& name, string* output) { void File::WriteStringToFileOrDie(const string& contents, const string& name) { FILE* file = fopen(name.c_str(), "wb"); - GOOGLE_CHECK(file != NULL); + GOOGLE_CHECK(file != NULL) + << "fopen(" << name << ", \"wb\"): " << strerror(errno); GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file), - contents.size()); - GOOGLE_CHECK(fclose(file) == 0); + contents.size()) + << "fwrite(" << name << "): " << strerror(errno); + GOOGLE_CHECK(fclose(file) == 0) + << "fclose(" << name << "): " << strerror(errno); } bool File::CreateDir(const string& name, int mode) { @@ -97,8 +100,10 @@ bool File::CreateDir(const string& name, int mode) { bool File::RecursivelyCreateDir(const string& path, int mode) { if (CreateDir(path, mode)) return true; + if (Exists(path)) return false; + // Try creating the parent. - string::size_type slashpos = path.find_first_of('/'); + string::size_type slashpos = path.find_last_of('/'); if (slashpos == string::npos) { // No parent given. return false; diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index cf754024..137cbcee 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -54,21 +54,19 @@ namespace protobuf { string Message::DebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); - TextFormat::Print(*this, &output_stream); + TextFormat::PrintToString(*this, &debug_string); return debug_string; } string Message::ShortDebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); TextFormat::Printer printer; printer.SetSingleLineMode(true); - printer.Print(*this, &output_stream); + printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. if (debug_string.size() > 0 && debug_string[debug_string.size() - 1] == ' ') { @@ -78,10 +76,22 @@ string Message::ShortDebugString() const { return debug_string; } +string Message::Utf8DebugString() const { + string debug_string; + + TextFormat::Printer printer; + printer.SetUseUtf8StringEscaping(true); + + printer.PrintToString(*this, &debug_string); + + return debug_string; +} + void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); } + // =========================================================================== // Internal class for parsing an ASCII representation of a Protocol Message. // This class makes use of the Protocol Message compiler's tokenizer found @@ -170,6 +180,23 @@ class TextFormat::Parser::ParserImpl { } } + void ReportWarning(int line, int col, const string& message) { + if (error_collector_ == NULL) { + if (line >= 0) { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << (line + 1) << ":" + << (col + 1) << ": " << message; + } else { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << message; + } + } else { + error_collector_->AddWarning(line, col, message); + } + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl); @@ -180,6 +207,13 @@ class TextFormat::Parser::ParserImpl { message); } + // Reports a warning with the given message with information indicating + // the position (as derived from the current token). + void ReportWarning(const string& message) { + ReportWarning(tokenizer_.current().line, tokenizer_.current().column, + message); + } + // Consumes the specified message with the given starting delimeter. // This method checks to see that the end delimeter at the conclusion of // the consumption matches the starting delimeter passed in here. @@ -270,6 +304,11 @@ class TextFormat::Parser::ParserImpl { DO(ConsumeFieldValue(message, reflection, field)); } + if (field->options().deprecated()) { + ReportWarning("text format contains deprecated field \"" + + field_name + "\""); + } + return true; } @@ -583,6 +622,10 @@ class TextFormat::Parser::ParserImpl { parser_->ReportError(line, column, message); } + virtual void AddWarning(int line, int column, const string& message) { + parser_->ReportWarning(line, column, message); + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector); TextFormat::Parser::ParserImpl* parser_; @@ -644,12 +687,16 @@ class TextFormat::Printer::TextGenerator { // Print text to the output stream. void Print(const string& str) { - Print(str.c_str()); + Print(str.data(), str.size()); } // Print text to the output stream. void Print(const char* text) { - int size = strlen(text); + Print(text, strlen(text)); + } + + // Print text to the output stream. + void Print(const char* text, int size) { int pos = 0; // The number of bytes we've written so far. for (int i = 0; i < size; i++) { @@ -799,7 +846,9 @@ bool TextFormat::Parser::ParseFieldValueFromString( TextFormat::Printer::Printer() : initial_indent_level_(0), - single_line_mode_(false) {} + single_line_mode_(false), + use_short_repeated_primitives_(false), + utf8_string_escaping_(false) {} TextFormat::Printer::~Printer() {} @@ -876,6 +925,14 @@ void TextFormat::Printer::PrintField(const Message& message, const Reflection* reflection, const FieldDescriptor* field, TextGenerator& generator) { + if (use_short_repeated_primitives_ && + field->is_repeated() && + field->cpp_type() != FieldDescriptor::CPPTYPE_STRING && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + PrintShortRepeatedField(message, reflection, field, generator); + return; + } + int count = 0; if (field->is_repeated()) { @@ -885,26 +942,7 @@ void TextFormat::Printer::PrintField(const Message& message, } for (int j = 0; j < count; ++j) { - if (field->is_extension()) { - generator.Print("["); - // We special-case MessageSet elements for compatibility with proto1. - if (field->containing_type()->options().message_set_wire_format() - && field->type() == FieldDescriptor::TYPE_MESSAGE - && field->is_optional() - && field->extension_scope() == field->message_type()) { - generator.Print(field->message_type()->full_name()); - } else { - generator.Print(field->full_name()); - } - generator.Print("]"); - } else { - if (field->type() == FieldDescriptor::TYPE_GROUP) { - // Groups must be serialized with their original capitalization. - generator.Print(field->message_type()->name()); - } else { - generator.Print(field->name()); - } - } + PrintFieldName(message, reflection, field, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (single_line_mode_) { @@ -926,16 +964,64 @@ void TextFormat::Printer::PrintField(const Message& message, PrintFieldValue(message, reflection, field, field_index, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (!single_line_mode_) { + if (single_line_mode_) { + generator.Print("} "); + } else { generator.Outdent(); + generator.Print("}\n"); + } + } else { + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); } - generator.Print("}"); } + } +} - if (single_line_mode_) { - generator.Print(" "); +void TextFormat::Printer::PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + // Print primitive repeated field in short form. + PrintFieldName(message, reflection, field, generator); + + int size = reflection->FieldSize(message, field); + generator.Print(": ["); + for (int i = 0; i < size; i++) { + if (i > 0) generator.Print(", "); + PrintFieldValue(message, reflection, field, i, generator); + } + if (single_line_mode_) { + generator.Print("] "); + } else { + generator.Print("]\n"); + } +} + +void TextFormat::Printer::PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + if (field->is_extension()) { + generator.Print("["); + // We special-case MessageSet elements for compatibility with proto1. + if (field->containing_type()->options().message_set_wire_format() + && field->type() == FieldDescriptor::TYPE_MESSAGE + && field->is_optional() + && field->extension_scope() == field->message_type()) { + generator.Print(field->message_type()->full_name()); + } else { + generator.Print(field->full_name()); + } + generator.Print("]"); + } else { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + // Groups must be serialized with their original capitalization. + generator.Print(field->message_type()->name()); } else { - generator.Print("\n"); + generator.Print(field->name()); } } } @@ -973,7 +1059,11 @@ void TextFormat::Printer::PrintFieldValue( reflection->GetStringReference(message, field, &scratch); generator.Print("\""); - generator.Print(CEscape(value)); + if (utf8_string_escaping_) { + generator.Print(strings::Utf8SafeCEscape(value)); + } else { + generator.Print(CEscape(value)); + } generator.Print("\""); break; diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 39a039d9..e78e1042 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -117,6 +117,24 @@ class LIBPROTOBUF_EXPORT TextFormat { single_line_mode_ = single_line_mode; } + // Set true to print repeated primitives in a format like: + // field_name: [1, 2, 3, 4] + // instead of printing each value on its own line. Short format applies + // only to primitive values -- i.e. everything except strings and + // sub-messages/groups. Note that at present this format is not recognized + // by the parser. + void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) { + use_short_repeated_primitives_ = use_short_repeated_primitives; + } + + // Set true to output UTF-8 instead of ASCII. The only difference + // is that bytes >= 0x80 in string fields will not be escaped, + // because they are assumed to be part of UTF-8 multi-byte + // sequences. + void SetUseUtf8StringEscaping(bool as_utf8) { + utf8_string_escaping_ = as_utf8; + } + private: // Forward declaration of an internal class used to print the text // output to the OutputStream (see text_format.cc for implementation). @@ -133,6 +151,19 @@ class LIBPROTOBUF_EXPORT TextFormat { const FieldDescriptor* field, TextGenerator& generator); + // Print a repeated primitive field in short form. + void PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + + // Print the name of a field -- i.e. everything that comes before the + // ':' for a single name/value pair. + void PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + // Outputs a textual representation of the value of the field supplied on // the message supplied or the default value if not set. void PrintFieldValue(const Message& message, @@ -150,6 +181,10 @@ class LIBPROTOBUF_EXPORT TextFormat { int initial_indent_level_; bool single_line_mode_; + + bool use_short_repeated_primitives_; + + bool utf8_string_escaping_; }; // Parses a text-format protocol message from the given input stream to diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 7c31e80f..ddf8ff7f 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -138,12 +138,53 @@ TEST_F(TextFormatTest, ShortDebugString) { proto_.ShortDebugString()); } +TEST_F(TextFormatTest, ShortPrimitiveRepeateds) { + proto_.set_optional_int32(123); + proto_.add_repeated_int32(456); + proto_.add_repeated_int32(789); + proto_.add_repeated_string("foo"); + proto_.add_repeated_string("bar"); + proto_.add_repeated_nested_message()->set_bb(2); + proto_.add_repeated_nested_message()->set_bb(3); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::FOO); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::BAR); + + TextFormat::Printer printer; + printer.SetUseShortRepeatedPrimitives(true); + string text; + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123\n" + "repeated_int32: [456, 789]\n" + "repeated_string: \"foo\"\n" + "repeated_string: \"bar\"\n" + "repeated_nested_message {\n bb: 2\n}\n" + "repeated_nested_message {\n bb: 3\n}\n" + "repeated_nested_enum: [FOO, BAR]\n", + text); + + // Try in single-line mode. + printer.SetSingleLineMode(true); + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123 " + "repeated_int32: [456, 789] " + "repeated_string: \"foo\" " + "repeated_string: \"bar\" " + "repeated_nested_message { bb: 2 } " + "repeated_nested_message { bb: 3 } " + "repeated_nested_enum: [FOO, BAR] ", + text); +} + + TEST_F(TextFormatTest, StringEscape) { // Set the string value to test. proto_.set_optional_string(kEscapeTestString); // Get the DebugString from the proto. string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); // Hardcode a correct value to test against. string correct_string = "optional_string: " @@ -152,12 +193,36 @@ TEST_F(TextFormatTest, StringEscape) { // Compare. EXPECT_EQ(correct_string, debug_string); + // UTF-8 string is the same as non-UTF-8 because + // the protocol buffer contains no UTF-8 text. + EXPECT_EQ(correct_string, utf8_debug_string); string expected_short_debug_string = "optional_string: " + kEscapeTestStringEscaped; EXPECT_EQ(expected_short_debug_string, proto_.ShortDebugString()); } +TEST_F(TextFormatTest, Utf8DebugString) { + // Set the string value to test. + proto_.set_optional_string("\350\260\267\346\255\214"); + + // Get the DebugString from the proto. + string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); + + // Hardcode a correct value to test against. + string correct_utf8_string = "optional_string: " + "\"\350\260\267\346\255\214\"" + "\n"; + string correct_string = "optional_string: " + "\"\\350\\260\\267\\346\\255\\214\"" + "\n"; + + // Compare. + EXPECT_EQ(correct_utf8_string, utf8_debug_string); + EXPECT_EQ(correct_string, debug_string); +} + TEST_F(TextFormatTest, PrintUnknownFields) { // Test printing of unknown fields in a message. @@ -603,10 +668,15 @@ class TextFormatParserTest : public testing::Test { void ExpectFailure(const string& input, const string& message, int line, int col, Message* proto) { + ExpectMessage(input, message, line, col, proto, false); + } + + void ExpectMessage(const string& input, const string& message, int line, + int col, Message* proto, bool expected_result) { TextFormat::Parser parser; MockErrorCollector error_collector; parser.RecordErrorsTo(&error_collector); - EXPECT_FALSE(parser.ParseFromString(input, proto)); + EXPECT_EQ(parser.ParseFromString(input, proto), expected_result); EXPECT_EQ(SimpleItoa(line) + ":" + SimpleItoa(col) + ": " + message + "\n", error_collector.text_); } @@ -625,6 +695,10 @@ class TextFormatParserTest : public testing::Test { strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line + 1, column + 1, message); } + + void AddWarning(int line, int column, const string& message) { + AddError(line, column, "WARNING:" + message); + } }; }; @@ -945,6 +1019,12 @@ TEST_F(TextFormatParserTest, FailsOnTokenizationError) { errors[0]); } +TEST_F(TextFormatParserTest, ParseDeprecatedField) { + unittest::TestDeprecatedFields message; + ExpectMessage("deprecated_int32: 42", + "WARNING:text format contains deprecated field " + "\"deprecated_int32\"", 1, 21, &message, true); +} class TextFormatMessageSetTest : public testing::Test { protected: @@ -991,5 +1071,4 @@ TEST_F(TextFormatMessageSetTest, Deserialize) { } // namespace text_format_unittest } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 03811de8..d51fa1e7 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -155,6 +155,10 @@ message TestAllTypes { optional string default_cord = 85 [ctype=CORD,default="123"]; } +message TestDeprecatedFields { + optional int32 deprecated_int32 = 1 [deprecated=true]; +} + // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { @@ -348,6 +352,12 @@ message TestEmptyMessageWithExtensions { extensions 1 to max; } +message TestMultipleExtensionRanges { + extensions 42; + extensions 4143 to 4243; + extensions 65536 to max; +} + // Test that really large tag numbers don't break anything. message TestReallyLargeTagNumber { // The largest possible tag number is 2^28 - 1, since the wire format uses @@ -372,13 +382,14 @@ message TestMutualRecursionB { } // Test that groups have disjoint field numbers from their siblings and -// parents. This is NOT possible in proto1; only proto2. When outputting -// proto1, the dup fields should be dropped. -message TestDupFieldNumber { - optional int32 a = 1; - optional group Foo = 2 { optional int32 a = 1; } - optional group Bar = 3 { optional int32 a = 1; } -} +// parents. This is NOT possible in proto1; only proto2. When attempting +// to compile with proto1, this will emit an error; so we only include it +// in protobuf_unittest_proto. +message TestDupFieldNumber { // NO_PROTO1 + optional int32 a = 1; // NO_PROTO1 + optional group Foo = 2 { optional int32 a = 1; } // NO_PROTO1 + optional group Bar = 3 { optional int32 a = 1; } // NO_PROTO1 +} // NO_PROTO1 // Needed for a Python test. @@ -468,6 +479,14 @@ message TestExtremeDefaultValues { // Using exponents optional float large_float = 12 [default = 2E8]; optional float small_negative_float = 13 [default = -8e-28]; + + // Text for nonfinite floating-point values. + optional double inf_double = 14 [default = inf]; + optional double neg_inf_double = 15 [default = -inf]; + optional double nan_double = 16 [default = nan]; + optional float inf_float = 17 [default = inf]; + optional float neg_inf_float = 18 [default = -inf]; + optional float nan_float = 19 [default = nan]; } // Test String and Bytes: string is for valid UTF-8 strings @@ -498,6 +517,25 @@ message TestPackedTypes { repeated ForeignEnum packed_enum = 103 [packed = true]; } +// A message with the same fields as TestPackedTypes, but without packing. Used +// to test packed <-> unpacked wire compatibility. +message TestUnpackedTypes { + repeated int32 unpacked_int32 = 90 [packed = false]; + repeated int64 unpacked_int64 = 91 [packed = false]; + repeated uint32 unpacked_uint32 = 92 [packed = false]; + repeated uint64 unpacked_uint64 = 93 [packed = false]; + repeated sint32 unpacked_sint32 = 94 [packed = false]; + repeated sint64 unpacked_sint64 = 95 [packed = false]; + repeated fixed32 unpacked_fixed32 = 96 [packed = false]; + repeated fixed64 unpacked_fixed64 = 97 [packed = false]; + repeated sfixed32 unpacked_sfixed32 = 98 [packed = false]; + repeated sfixed64 unpacked_sfixed64 = 99 [packed = false]; + repeated float unpacked_float = 100 [packed = false]; + repeated double unpacked_double = 101 [packed = false]; + repeated bool unpacked_bool = 102 [packed = false]; + repeated ForeignEnum unpacked_enum = 103 [packed = false]; +} + message TestPackedExtensions { extensions 1 to max; } @@ -519,6 +557,47 @@ extend TestPackedExtensions { repeated ForeignEnum packed_enum_extension = 103 [packed = true]; } +// Used by ExtensionSetTest/DynamicExtensions. The test actually builds +// a set of extensions to TestAllExtensions dynamically, based on the fields +// of this message type. +message TestDynamicExtensions { + enum DynamicEnumType { + DYNAMIC_FOO = 2200; + DYNAMIC_BAR = 2201; + DYNAMIC_BAZ = 2202; + } + message DynamicMessageType { + optional int32 dynamic_field = 2100; + } + + optional fixed32 scalar_extension = 2000; + optional ForeignEnum enum_extension = 2001; + optional DynamicEnumType dynamic_enum_extension = 2002; + + optional ForeignMessage message_extension = 2003; + optional DynamicMessageType dynamic_message_extension = 2004; + + repeated string repeated_extension = 2005; + repeated sint32 packed_extension = 2006 [packed = true]; +} + +message TestRepeatedScalarDifferentTagSizes { + // Parsing repeated fixed size values used to fail. This message needs to be + // used in order to get a tag of the right size; all of the repeated fields + // in TestAllTypes didn't trigger the check. + repeated fixed32 repeated_fixed32 = 12; + // Check for a varint type, just for good measure. + repeated int32 repeated_int32 = 13; + + // These have two-byte tags. + repeated fixed64 repeated_fixed64 = 2046; + repeated int64 repeated_int64 = 2047; + + // Three byte tags. + repeated float repeated_float = 262142; + repeated uint64 repeated_uint64 = 262143; +} + // Test that RPC services work. message FooRequest {} message FooResponse {} diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto index 6ad2dab3..bc0b7c16 100644 --- a/src/google/protobuf/unittest_enormous_descriptor.proto +++ b/src/google/protobuf/unittest_enormous_descriptor.proto @@ -35,6 +35,7 @@ // A proto file that has an extremely large descriptor. Used to test that // descriptors over 64k don't break the string literal length limit in Java. + package google.protobuf; option java_package = "com.google.protobuf"; diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 318ffafe..e1f8b838 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include #include @@ -50,13 +51,12 @@ UnknownFieldSet::~UnknownFieldSet() { delete fields_; } -void UnknownFieldSet::Clear() { - if (fields_ != NULL) { - for (int i = 0; i < fields_->size(); i++) { - (*fields_)[i].Delete(); - } - fields_->clear(); +void UnknownFieldSet::ClearFallback() { + GOOGLE_DCHECK(fields_ != NULL); + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); } + fields_->clear(); } void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index d6ca70fc..84c2e2b6 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -66,7 +66,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { ~UnknownFieldSet(); // Remove all fields. - void Clear(); + inline void Clear(); // Is this set empty? inline bool empty() const; @@ -119,6 +119,8 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { } private: + void ClearFallback(); + vector* fields_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); @@ -180,6 +182,12 @@ class LIBPROTOBUF_EXPORT UnknownField { // =================================================================== // inline implementations +inline void UnknownFieldSet::Clear() { + if (fields_ != NULL) { + ClearFallback(); + } +} + inline bool UnknownFieldSet::empty() const { return fields_ == NULL || fields_->empty(); } diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 5aa67727..831a5794 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -391,7 +391,12 @@ bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, // If that failed, check if the field is an extension. if (field == NULL && descriptor->IsExtensionNumber(field_number)) { - field = message_reflection->FindKnownExtensionByNumber(field_number); + if (input->GetExtensionPool() == NULL) { + field = message_reflection->FindKnownExtensionByNumber(field_number); + } else { + field = input->GetExtensionPool() + ->FindExtensionByNumber(descriptor, field_number); + } } // If that failed, but we're a MessageSet, and this is the tag for a @@ -419,52 +424,67 @@ bool WireFormat::ParseAndMergeField( io::CodedInputStream* input) { const Reflection* message_reflection = message->GetReflection(); - if (field == NULL || - WireFormatLite::GetTagWireType(tag) != WireTypeForField(field)) { - // We don't recognize this field. Either the field number is unknown - // or the wire type doesn't match. Put it in our unknown field set. - return SkipField(input, tag, - message_reflection->MutableUnknownFields(message)); + enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format; + + if (field == NULL) { + value_format = UNKNOWN; + } else if (WireFormatLite::GetTagWireType(tag) == + WireTypeForFieldType(field->type())) { + value_format = NORMAL_FORMAT; + } else if (field->is_packable() && + WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + value_format = PACKED_FORMAT; + } else { + // We don't recognize this field. Either the field number is unknown + // or the wire type doesn't match. Put it in our unknown field set. + value_format = UNKNOWN; } - if (field->options().packed()) { + if (value_format == UNKNOWN) { + return SkipField(input, tag, + message_reflection->MutableUnknownFields(message)); + } else if (value_format == PACKED_FORMAT) { uint32 length; if (!input->ReadVarint32(&length)) return false; io::CodedInputStream::Limit limit = input->PushLimit(length); switch (field->type()) { -#define HANDLE_PACKED_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ while (input->BytesUntilLimit() > 0) { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } \ break; \ } - HANDLE_PACKED_TYPE( INT32, Int32, int32, Int32) - HANDLE_PACKED_TYPE( INT64, Int64, int64, Int64) - HANDLE_PACKED_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_PACKED_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_PACKED_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_PACKED_TYPE(UINT64, UInt64, uint64, UInt64) + HANDLE_PACKED_TYPE( INT32, int32, Int32) + HANDLE_PACKED_TYPE( INT64, int64, Int64) + HANDLE_PACKED_TYPE(SINT32, int32, Int32) + HANDLE_PACKED_TYPE(SINT64, int64, Int64) + HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) + HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) - HANDLE_PACKED_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_PACKED_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_PACKED_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_PACKED_TYPE(SFIXED64, SFixed64, int64, Int64) + HANDLE_PACKED_TYPE( FIXED32, uint32, UInt32) + HANDLE_PACKED_TYPE( FIXED64, uint64, UInt64) + HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) + HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) - HANDLE_PACKED_TYPE(FLOAT , Float , float , Float ) - HANDLE_PACKED_TYPE(DOUBLE, Double, double, Double) + HANDLE_PACKED_TYPE(FLOAT , float , Float ) + HANDLE_PACKED_TYPE(DOUBLE, double, Double) - HANDLE_PACKED_TYPE(BOOL, Bool, bool, Bool) + HANDLE_PACKED_TYPE(BOOL, bool, Bool) #undef HANDLE_PACKED_TYPE case FieldDescriptor::TYPE_ENUM: { while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -487,11 +507,14 @@ bool WireFormat::ParseAndMergeField( input->PopLimit(limit); } else { + // Non-packed value (value_format == NORMAL_FORMAT) switch (field->type()) { -#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ if (field->is_repeated()) { \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } else { \ @@ -500,31 +523,28 @@ bool WireFormat::ParseAndMergeField( break; \ } - HANDLE_TYPE( INT32, Int32, int32, Int32) - HANDLE_TYPE( INT64, Int64, int64, Int64) - HANDLE_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) - - HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) - - HANDLE_TYPE(FLOAT , Float , float , Float ) - HANDLE_TYPE(DOUBLE, Double, double, Double) + HANDLE_TYPE( INT32, int32, Int32) + HANDLE_TYPE( INT64, int64, Int64) + HANDLE_TYPE(SINT32, int32, Int32) + HANDLE_TYPE(SINT64, int64, Int64) + HANDLE_TYPE(UINT32, uint32, UInt32) + HANDLE_TYPE(UINT64, uint64, UInt64) - HANDLE_TYPE(BOOL, Bool, bool, Bool) + HANDLE_TYPE( FIXED32, uint32, UInt32) + HANDLE_TYPE( FIXED64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, int32, Int32) + HANDLE_TYPE(SFIXED64, int64, Int64) - HANDLE_TYPE(STRING, String, string, String) - HANDLE_TYPE(BYTES, Bytes, string, String) + HANDLE_TYPE(FLOAT , float , Float ) + HANDLE_TYPE(DOUBLE, double, Double) + HANDLE_TYPE(BOOL, bool, Bool) #undef HANDLE_TYPE case FieldDescriptor::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -544,13 +564,38 @@ bool WireFormat::ParseAndMergeField( break; } + // Handle strings separately so that we can optimize the ctype=CORD case. + case FieldDescriptor::TYPE_STRING: { + string value; + if (!WireFormatLite::ReadString(input, &value)) return false; + VerifyUTF8String(value.data(), value.length(), PARSE); + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } + + case FieldDescriptor::TYPE_BYTES: { + string value; + if (!WireFormatLite::ReadBytes(input, &value)) return false; + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } case FieldDescriptor::TYPE_GROUP: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag), @@ -562,9 +607,11 @@ bool WireFormat::ParseAndMergeField( case FieldDescriptor::TYPE_MESSAGE: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadMessage(input, sub_message)) return false; @@ -782,23 +829,23 @@ void WireFormat::SerializeFieldWithCachedSizes( // Handle strings separately so that we can get string references // instead of copying. case FieldDescriptor::TYPE_STRING: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - VerifyUTF8String(value.data(), value.length(), SERIALIZE); - WireFormatLite::WriteString(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + VerifyUTF8String(value.data(), value.length(), SERIALIZE); + WireFormatLite::WriteString(field->number(), value, output); break; } case FieldDescriptor::TYPE_BYTES: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - WireFormatLite::WriteBytes(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + WireFormatLite::WriteBytes(field->number(), value, output); break; } } @@ -961,14 +1008,14 @@ int WireFormat::FieldDataOnlyByteSize( // instead of copying. case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_BYTES: { - for (int j = 0; j < count; j++) { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - data_size += WireFormatLite::StringSize(value); - } + for (int j = 0; j < count; j++) { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + data_size += WireFormatLite::StringSize(value); + } break; } } diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 5d09803a..d347d116 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -32,14 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #include - -#include - #include -#include +#include #include #include @@ -187,6 +186,174 @@ void FieldSkipper::SkipUnknownEnum( // Nothing. } +bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input, + bool (*is_valid)(int), + RepeatedField* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + int value; + if (!google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, WireFormatLite::TYPE_ENUM>(input, &value)) { + return false; + } + if (is_valid(value)) { + values->Add(value); + } + } + input->PopLimit(limit); + return true; +} + +void WireFormatLite::WriteInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt32NoTag(value, output); +} +void WireFormatLite::WriteInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt64NoTag(value, output); +} +void WireFormatLite::WriteUInt32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt32NoTag(value, output); +} +void WireFormatLite::WriteUInt64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt64NoTag(value, output); +} +void WireFormatLite::WriteSInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt32NoTag(value, output); +} +void WireFormatLite::WriteSInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt64NoTag(value, output); +} +void WireFormatLite::WriteFixed32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFixed32NoTag(value, output); +} +void WireFormatLite::WriteFixed64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteFixed64NoTag(value, output); +} +void WireFormatLite::WriteSFixed32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteSFixed32NoTag(value, output); +} +void WireFormatLite::WriteSFixed64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteSFixed64NoTag(value, output); +} +void WireFormatLite::WriteFloat(int field_number, float value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFloatNoTag(value, output); +} +void WireFormatLite::WriteDouble(int field_number, double value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteDoubleNoTag(value, output); +} +void WireFormatLite::WriteBool(int field_number, bool value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteBoolNoTag(value, output); +} +void WireFormatLite::WriteEnum(int field_number, int value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteEnumNoTag(value, output); +} + +void WireFormatLite::WriteString(int field_number, const string& value, + io::CodedOutputStream* output) { + // String is for UTF-8 text only + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} +void WireFormatLite::WriteBytes(int field_number, const string& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} + + +void WireFormatLite::WriteGroup(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessage(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + value.SerializeWithCachedSizes(output); +} + +void WireFormatLite::WriteGroupMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + const int size = value.GetCachedSize(); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessageMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } +} + +bool WireFormatLite::ReadString(io::CodedInputStream* input, + string* value) { + // String is for UTF-8 text only + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->InternalReadStringInline(value, length)) return false; + return true; +} +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, + string* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + return input->InternalReadStringInline(value, length); +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index 9b7a4010..e3d5b2d8 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -46,15 +46,18 @@ namespace google { namespace protobuf { + template class RepeatedField; // repeated_field.h namespace io { - class CodedInputStream; // coded_stream.h - class CodedOutputStream; // coded_stream.h + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h } } namespace protobuf { namespace internal { +class StringPieceField; + // This class is for internal use by the protocol buffer library and by // protocol-complier-generated message classes. It must not be called // directly by clients. @@ -183,14 +186,21 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // required string message = 3; // } // } + static const int kMessageSetItemNumber = 1; + static const int kMessageSetTypeIdNumber = 2; + static const int kMessageSetMessageNumber = 3; static const int kMessageSetItemStartTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_START_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_START_GROUP); static const int kMessageSetItemEndTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_END_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_END_GROUP); static const int kMessageSetTypeIdTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(2, WireFormatLite::WIRETYPE_VARINT); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber, + WireFormatLite::WIRETYPE_VARINT); static const int kMessageSetMessageTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(3, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); // Byte size of all tags of a MessageSet::Item combined. static const int kMessageSetItemTagsSize; @@ -227,23 +237,59 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // Read fields, not including tags. The assumption is that you already // read the tag to determine what field to read. - static inline bool ReadInt32 (input, int32* value); - static inline bool ReadInt64 (input, int64* value); - static inline bool ReadUInt32 (input, uint32* value); - static inline bool ReadUInt64 (input, uint64* value); - static inline bool ReadSInt32 (input, int32* value); - static inline bool ReadSInt64 (input, int64* value); - static inline bool ReadFixed32 (input, uint32* value); - static inline bool ReadFixed64 (input, uint64* value); - static inline bool ReadSFixed32(input, int32* value); - static inline bool ReadSFixed64(input, int64* value); - static inline bool ReadFloat (input, float* value); - static inline bool ReadDouble (input, double* value); - static inline bool ReadBool (input, bool* value); - static inline bool ReadEnum (input, int* value); - - static inline bool ReadString(input, string* value); - static inline bool ReadBytes (input, string* value); + + // For primitive fields, we just use a templatized routine parameterized by + // the represented type and the FieldType. These are specialized with the + // appropriate definition for each declared type. + template + static inline bool ReadPrimitive(input, CType* value) INL; + + // Reads repeated primitive values, with optimizations for repeats. + // tag_size and tag should both be compile-time constants provided by the + // protocol compiler. + template + static inline bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField* value) INL; + + // Identical to ReadRepeatedPrimitive, except will not inline the + // implementation. + template + static bool ReadRepeatedPrimitiveNoInline(int tag_size, + uint32 tag, + input, + RepeatedField* value); + + // Reads a primitive value directly from the provided buffer. It returns a + // pointer past the segment of data that was read. + // + // This is only implemented for the types with fixed wire size, e.g. + // float, double, and the (s)fixed* types. + template + static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, + CType* value) INL; + + // Reads a primitive packed field. + // + // This is only implemented for packable types. + template + static inline bool ReadPackedPrimitive(input, + RepeatedField* value) INL; + + // Identical to ReadPackedPrimitive, except will not inline the + // implementation. + template + static bool ReadPackedPrimitiveNoInline(input, RepeatedField* value); + + // Read a packed enum field. Values for which is_valid() returns false are + // dropped. + static bool ReadPackedEnumNoInline(input, + bool (*is_valid)(int), + RepeatedField* value); + + static bool ReadString(input, string* value); + static bool ReadBytes (input, string* value); static inline bool ReadGroup (field_number, input, MessageLite* value); static inline bool ReadMessage(input, MessageLite* value); @@ -279,38 +325,44 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline void WriteEnumNoTag (int value, output) INL; // Write fields, including tags. - static inline void WriteInt32 (field_number, int32 value, output) INL; - static inline void WriteInt64 (field_number, int64 value, output) INL; - static inline void WriteUInt32 (field_number, uint32 value, output) INL; - static inline void WriteUInt64 (field_number, uint64 value, output) INL; - static inline void WriteSInt32 (field_number, int32 value, output) INL; - static inline void WriteSInt64 (field_number, int64 value, output) INL; - static inline void WriteFixed32 (field_number, uint32 value, output) INL; - static inline void WriteFixed64 (field_number, uint64 value, output) INL; - static inline void WriteSFixed32(field_number, int32 value, output) INL; - static inline void WriteSFixed64(field_number, int64 value, output) INL; - static inline void WriteFloat (field_number, float value, output) INL; - static inline void WriteDouble (field_number, double value, output) INL; - static inline void WriteBool (field_number, bool value, output) INL; - static inline void WriteEnum (field_number, int value, output) INL; - - static inline void WriteString(field_number, const string& value, output) INL; - static inline void WriteBytes (field_number, const string& value, output) INL; - - static inline void WriteGroup( - field_number, const MessageLite& value, output) INL; - static inline void WriteMessage( - field_number, const MessageLite& value, output) INL; + static void WriteInt32 (field_number, int32 value, output); + static void WriteInt64 (field_number, int64 value, output); + static void WriteUInt32 (field_number, uint32 value, output); + static void WriteUInt64 (field_number, uint64 value, output); + static void WriteSInt32 (field_number, int32 value, output); + static void WriteSInt64 (field_number, int64 value, output); + static void WriteFixed32 (field_number, uint32 value, output); + static void WriteFixed64 (field_number, uint64 value, output); + static void WriteSFixed32(field_number, int32 value, output); + static void WriteSFixed64(field_number, int64 value, output); + static void WriteFloat (field_number, float value, output); + static void WriteDouble (field_number, double value, output); + static void WriteBool (field_number, bool value, output); + static void WriteEnum (field_number, int value, output); + + static void WriteString(field_number, const string& value, output); + static void WriteBytes (field_number, const string& value, output); + + static void WriteGroup( + field_number, const MessageLite& value, output); + static void WriteMessage( + field_number, const MessageLite& value, output); + // Like above, but these will check if the output stream has enough + // space to write directly to a flat array. + static void WriteGroupMaybeToArray( + field_number, const MessageLite& value, output); + static void WriteMessageMaybeToArray( + field_number, const MessageLite& value, output); // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The // pointer must point at an instance of MessageType, *not* a subclass (or // the subclass must not override SerializeWithCachedSizes()). template static inline void WriteGroupNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); template static inline void WriteMessageNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); #undef output #define output uint8* target @@ -426,6 +478,16 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline int MessageSizeNoVirtual(const MessageType& value); private: + // A helper method for the repeated primitive reader. This method has + // optimizations for primitive types that have fixed size on the wire, and + // can be read using potentially faster paths. + template + static inline bool ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + google::protobuf::io::CodedInputStream* input, + RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static const CppType kFieldTypeToCppTypeMap[]; static const WireFormatLite::WireType kWireTypeForFieldType[]; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index eb9155e9..d7b2c302 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -39,7 +39,9 @@ #include #include #include +#include #include +#include #include @@ -47,106 +49,295 @@ namespace google { namespace protobuf { namespace internal { -inline bool WireFormatLite::ReadInt32(io::CodedInputStream* input, - int32* value) { +// Implementation details of ReadPrimitive. + +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadUInt32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { return input->ReadVarint32(value); } -inline bool WireFormatLite::ReadUInt64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { return input->ReadVarint64(value); } -inline bool WireFormatLite::ReadSInt32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = ZigZagDecode32(temp); return true; } -inline bool WireFormatLite::ReadSInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = ZigZagDecode64(temp); return true; } -inline bool WireFormatLite::ReadFixed32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { return input->ReadLittleEndian32(value); } -inline bool WireFormatLite::ReadFixed64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { return input->ReadLittleEndian64(value); } -inline bool WireFormatLite::ReadSFixed32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadSFixed64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadFloat(io::CodedInputStream* input, - float* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + float* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = DecodeFloat(temp); return true; } -inline bool WireFormatLite::ReadDouble(io::CodedInputStream* input, - double* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + double* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = DecodeDouble(temp); return true; } -inline bool WireFormatLite::ReadBool(io::CodedInputStream* input, - bool* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + bool* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = temp != 0; return true; } -inline bool WireFormatLite::ReadEnum(io::CodedInputStream* input, - int* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadString(io::CodedInputStream* input, - string* value) { - // String is for UTF-8 text only - uint32 length; - if (!input->ReadVarint32(&length)) return false; - if (!input->ReadString(value, length)) return false; +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint32, WireFormatLite::TYPE_FIXED32>( + const uint8* buffer, + uint32* value) { + return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint64, WireFormatLite::TYPE_FIXED64>( + const uint8* buffer, + uint64* value) { + return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int32, WireFormatLite::TYPE_SFIXED32>( + const uint8* buffer, + int32* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int64, WireFormatLite::TYPE_SFIXED64>( + const uint8* buffer, + int64* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + float, WireFormatLite::TYPE_FLOAT>( + const uint8* buffer, + float* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = DecodeFloat(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + double, WireFormatLite::TYPE_DOUBLE>( + const uint8* buffer, + double* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = DecodeDouble(temp); + return buffer; +} + +template +inline bool WireFormatLite::ReadRepeatedPrimitive(int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + int elements_already_reserved = values->Capacity() - values->size(); + while (elements_already_reserved > 0 && input->ExpectTag(tag)) { + if (!ReadPrimitive(input, &value)) return false; + values->AddAlreadyReserved(value); + elements_already_reserved--; + } + return true; +} + +template +inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + GOOGLE_DCHECK_EQ(UInt32Size(tag), tag_size); + CType value; + if (!ReadPrimitive(input, &value)) + return false; + values->Add(value); + + // For fixed size values, repeated values can be read more quickly by + // reading directly from a raw array. + // + // We can get a tight loop by only reading as many elements as can be + // added to the RepeatedField without having to do any resizing. Additionally, + // we only try to read as many elements as are available from the current + // buffer space. Doing so avoids having to perform boundary checks when + // reading the value: the maximum number of elements that can be read is + // known outside of the loop. + const void* void_pointer; + int size; + input->GetDirectBufferPointerInline(&void_pointer, &size); + if (size > 0) { + const uint8* buffer = reinterpret_cast(void_pointer); + // The number of bytes each type occupies on the wire. + const int per_value_size = tag_size + sizeof(value); + + int elements_available = min(values->Capacity() - values->size(), + size / per_value_size); + int num_read = 0; + while (num_read < elements_available && + (buffer = io::CodedInputStream::ExpectTagFromArray( + buffer, tag)) != NULL) { + buffer = ReadPrimitiveFromArray(buffer, &value); + values->AddAlreadyReserved(value); + ++num_read; + } + const int read_bytes = num_read * per_value_size; + if (read_bytes > 0) { + input->Skip(read_bytes); + } + } return true; } -inline bool WireFormatLite::ReadBytes(io::CodedInputStream* input, - string* value) { + +// Specializations of ReadRepeatedPrimitive for the fixed size types, which use +// the optimized code path. +#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \ +template <> \ +inline bool WireFormatLite::ReadRepeatedPrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + int tag_size, \ + uint32 tag, \ + io::CodedInputStream* input, \ + RepeatedField* values) { \ + return ReadRepeatedFixedSizePrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + tag_size, tag, input, values); \ +} + +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE); + +#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE + +template +bool WireFormatLite::ReadRepeatedPrimitiveNoInline( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* value) { + return ReadRepeatedPrimitive( + tag_size, tag, input, value); +} + +template +inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input, + RepeatedField* values) { uint32 length; if (!input->ReadVarint32(&length)) return false; - return input->ReadString(value, length); + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + } + input->PopLimit(limit); + return true; +} + +template +bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, + RepeatedField* values) { + return ReadPackedPrimitive(input, values); } @@ -270,107 +461,6 @@ inline void WireFormatLite::WriteEnumNoTag(int value, output->WriteVarint32SignExtended(value); } -inline void WireFormatLite::WriteInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt32NoTag(value, output); -} -inline void WireFormatLite::WriteInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt64NoTag(value, output); -} -inline void WireFormatLite::WriteUInt32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt32NoTag(value, output); -} -inline void WireFormatLite::WriteUInt64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt64NoTag(value, output); -} -inline void WireFormatLite::WriteSInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt32NoTag(value, output); -} -inline void WireFormatLite::WriteSInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt64NoTag(value, output); -} -inline void WireFormatLite::WriteFixed32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteFixed64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteSFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteSFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteFloat(int field_number, float value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFloatNoTag(value, output); -} -inline void WireFormatLite::WriteDouble(int field_number, double value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteDoubleNoTag(value, output); -} -inline void WireFormatLite::WriteBool(int field_number, bool value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteBoolNoTag(value, output); -} -inline void WireFormatLite::WriteEnum(int field_number, int value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteEnumNoTag(value, output); -} - -inline void WireFormatLite::WriteString(int field_number, const string& value, - io::CodedOutputStream* output) { - // String is for UTF-8 text only - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} -inline void WireFormatLite::WriteBytes(int field_number, const string& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} - - -inline void WireFormatLite::WriteGroup(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_START_GROUP, output); - value.SerializeWithCachedSizes(output); - WriteTag(field_number, WIRETYPE_END_GROUP, output); -} -inline void WireFormatLite::WriteMessage(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.GetCachedSize()); - value.SerializeWithCachedSizes(output); -} - template inline void WireFormatLite::WriteGroupNoVirtual(int field_number, const MessageType& value, diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 51960ee7..867970c4 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -126,6 +126,38 @@ TEST(WireFormatTest, ParsePacked) { TestUtil::ExpectPackedFieldsSet(dest); } +TEST(WireFormatTest, ParsePackedFromUnpacked) { + // Serialize using the generated code. + unittest::TestUnpackedTypes source; + TestUtil::SetUnpackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestPackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectPackedFieldsSet(dest); +} + +TEST(WireFormatTest, ParseUnpackedFromPacked) { + // Serialize using the generated code. + unittest::TestPackedTypes source; + TestUtil::SetPackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestUnpackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectUnpackedFieldsSet(dest); +} + TEST(WireFormatTest, ParsePackedExtensions) { unittest::TestPackedExtensions source, dest; string data; @@ -568,6 +600,45 @@ TEST(WireFormatTest, ZigZag) { LL(-75123905439571256)))); } +TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) { + // At one point checks would trigger when parsing repeated fixed scalar + // fields. + protobuf_unittest::TestRepeatedScalarDifferentTagSizes msg1, msg2; + for (int i = 0; i < 100; ++i) { + msg1.add_repeated_fixed32(i); + msg1.add_repeated_int32(i); + msg1.add_repeated_fixed64(i); + msg1.add_repeated_int64(i); + msg1.add_repeated_float(i); + msg1.add_repeated_uint64(i); + } + + // Make sure that we have a variety of tag sizes. + const google::protobuf::Descriptor* desc = msg1.GetDescriptor(); + const google::protobuf::FieldDescriptor* field; + field = desc->FindFieldByName("repeated_fixed32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_fixed64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_float"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_uint64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + + EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString())); + EXPECT_EQ(msg1.DebugString(), msg2.DebugString()); +} + class WireFormatInvalidInputTest : public testing::Test { protected: // Make a serialized TestAllTypes in which the field optional_nested_message diff --git a/vsprojects/libprotobuf-lite.vcproj b/vsprojects/libprotobuf-lite.vcproj index 7e7b1e66..8c0ec9f3 100644 --- a/vsprojects/libprotobuf-lite.vcproj +++ b/vsprojects/libprotobuf-lite.vcproj @@ -1,270 +1,270 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsprojects/libprotobuf.vcproj b/vsprojects/libprotobuf.vcproj index d6258675..0303a6e9 100644 --- a/vsprojects/libprotobuf.vcproj +++ b/vsprojects/libprotobuf.vcproj @@ -1,430 +1,430 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsprojects/lite-test.vcproj b/vsprojects/lite-test.vcproj index 50153cfb..f66556ab 100644 --- a/vsprojects/lite-test.vcproj +++ b/vsprojects/lite-test.vcproj @@ -1,273 +1,273 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsprojects/protobuf.sln b/vsprojects/protobuf.sln index 9f2e8b61..6925a861 100644 --- a/vsprojects/protobuf.sln +++ b/vsprojects/protobuf.sln @@ -1,80 +1,80 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf", "libprotobuf.vcproj", "{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotoc", "libprotoc.vcproj", "{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}" - ProjectSection(ProjectDependencies) = postProject - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "protoc.vcproj", "{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}" - ProjectSection(ProjectDependencies) = postProject - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests.vcproj", "{4DF72760-C055-40A5-A77E-30A17E2AC2DB}" - ProjectSection(ProjectDependencies) = postProject - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} - {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} = {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} - {3AF54C8A-10BF-4332-9147-F68ED9862032} = {3AF54C8A-10BF-4332-9147-F68ED9862032} - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\gtest\msvc\gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "..\gtest\msvc\gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf-lite", "libprotobuf-lite.vcproj", "{49EA010D-706F-4BE2-A397-77854B72A040}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lite-test", "lite-test.vcproj", "{12015ACE-42BE-4952-A5A0-44A9A46908E2}" - ProjectSection(ProjectDependencies) = postProject - {49EA010D-706F-4BE2-A397-77854B72A040} = {49EA010D-706F-4BE2-A397-77854B72A040} - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.ActiveCfg = Debug|Win32 - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.Build.0 = Debug|Win32 - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.ActiveCfg = Release|Win32 - {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.Build.0 = Release|Win32 - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.Build.0 = Debug|Win32 - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.ActiveCfg = Release|Win32 - {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.Build.0 = Release|Win32 - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.ActiveCfg = Debug|Win32 - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.Build.0 = Debug|Win32 - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.ActiveCfg = Release|Win32 - {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.Build.0 = Release|Win32 - {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.ActiveCfg = Debug|Win32 - {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.Build.0 = Debug|Win32 - {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.ActiveCfg = Release|Win32 - {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.Build.0 = Release|Win32 - {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.ActiveCfg = Debug|Win32 - {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.Build.0 = Debug|Win32 - {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.ActiveCfg = Release|Win32 - {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.Build.0 = Release|Win32 - {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.ActiveCfg = Debug|Win32 - {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.Build.0 = Debug|Win32 - {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.ActiveCfg = Release|Win32 - {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.Build.0 = Release|Win32 - {49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.ActiveCfg = Debug|Win32 - {49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.Build.0 = Debug|Win32 - {49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.ActiveCfg = Release|Win32 - {49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.Build.0 = Release|Win32 - {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.ActiveCfg = Debug|Win32 - {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.Build.0 = Debug|Win32 - {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.ActiveCfg = Release|Win32 - {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf", "libprotobuf.vcproj", "{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotoc", "libprotoc.vcproj", "{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}" + ProjectSection(ProjectDependencies) = postProject + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "protoc.vcproj", "{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}" + ProjectSection(ProjectDependencies) = postProject + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests.vcproj", "{4DF72760-C055-40A5-A77E-30A17E2AC2DB}" + ProjectSection(ProjectDependencies) = postProject + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30} + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} = {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} + {3AF54C8A-10BF-4332-9147-F68ED9862032} = {3AF54C8A-10BF-4332-9147-F68ED9862032} + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\gtest\msvc\gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "..\gtest\msvc\gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf-lite", "libprotobuf-lite.vcproj", "{49EA010D-706F-4BE2-A397-77854B72A040}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lite-test", "lite-test.vcproj", "{12015ACE-42BE-4952-A5A0-44A9A46908E2}" + ProjectSection(ProjectDependencies) = postProject + {49EA010D-706F-4BE2-A397-77854B72A040} = {49EA010D-706F-4BE2-A397-77854B72A040} + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.Build.0 = Debug|Win32 + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.ActiveCfg = Release|Win32 + {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.Build.0 = Release|Win32 + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.ActiveCfg = Debug|Win32 + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.Build.0 = Debug|Win32 + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.ActiveCfg = Release|Win32 + {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.Build.0 = Release|Win32 + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.ActiveCfg = Debug|Win32 + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.Build.0 = Debug|Win32 + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.ActiveCfg = Release|Win32 + {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.Build.0 = Release|Win32 + {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.ActiveCfg = Debug|Win32 + {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.Build.0 = Debug|Win32 + {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.ActiveCfg = Release|Win32 + {4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.Build.0 = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.ActiveCfg = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.Build.0 = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.ActiveCfg = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.Build.0 = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.ActiveCfg = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.Build.0 = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.ActiveCfg = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.Build.0 = Release|Win32 + {49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.ActiveCfg = Debug|Win32 + {49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.Build.0 = Debug|Win32 + {49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.ActiveCfg = Release|Win32 + {49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.Build.0 = Release|Win32 + {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.Build.0 = Debug|Win32 + {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.ActiveCfg = Release|Win32 + {12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/vsprojects/tests.vcproj b/vsprojects/tests.vcproj index 013ff1b4..c3976a78 100644 --- a/vsprojects/tests.vcproj +++ b/vsprojects/tests.vcproj @@ -1,573 +1,573 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3