Merge pull request #849 from pherl/master

Integrate google internal changes.
pull/860/head
Jisi Liu 9 years ago
commit 878b603d32
  1. 2
      Makefile.am
  2. 352
      java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  3. 15
      java/src/main/java/com/google/protobuf/TextFormat.java
  4. 296
      java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
  5. 10
      java/src/main/java/com/google/protobuf/Utf8.java
  6. 4
      java/src/test/java/com/google/protobuf/DescriptorsTest.java
  7. 16
      java/src/test/java/com/google/protobuf/TextFormatTest.java
  8. 180
      java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
  9. 10
      java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
  10. 8
      objectivec/google/protobuf/Descriptor.pbobjc.h
  11. 15
      objectivec/google/protobuf/Descriptor.pbobjc.m
  12. 43
      python/google/protobuf/descriptor.py
  13. 2
      python/google/protobuf/internal/decoder.py
  14. 3
      python/google/protobuf/internal/descriptor_pool_test.py
  15. 36
      python/google/protobuf/internal/descriptor_test.py
  16. 2
      python/google/protobuf/internal/encoder.py
  17. 525
      python/google/protobuf/internal/json_format_test.py
  18. 1
      python/google/protobuf/internal/message_factory_test.py
  19. 15
      python/google/protobuf/internal/message_test.py
  20. 4
      python/google/protobuf/internal/missing_enum_values.proto
  21. 6
      python/google/protobuf/internal/proto_builder_test.py
  22. 2
      python/google/protobuf/internal/python_message.py
  23. 6
      python/google/protobuf/internal/reflection_test.py
  24. 27
      python/google/protobuf/internal/symbol_database_test.py
  25. 3
      python/google/protobuf/internal/text_format_test.py
  26. 3
      python/google/protobuf/internal/type_checkers.py
  27. 14
      python/google/protobuf/internal/unknown_fields_test.py
  28. 601
      python/google/protobuf/json_format.py
  29. 2
      python/google/protobuf/message_factory.py
  30. 43
      python/google/protobuf/proto_builder.py
  31. 41
      python/google/protobuf/pyext/descriptor.cc
  32. 2
      python/google/protobuf/pyext/descriptor.h
  33. 88
      python/google/protobuf/pyext/descriptor_containers.cc
  34. 1
      python/google/protobuf/pyext/descriptor_containers.h
  35. 112
      python/google/protobuf/pyext/descriptor_pool.cc
  36. 15
      python/google/protobuf/pyext/descriptor_pool.h
  37. 3
      python/google/protobuf/pyext/extension_dict.cc
  38. 153
      python/google/protobuf/pyext/message.cc
  39. 13
      python/google/protobuf/pyext/message.h
  40. 28
      python/google/protobuf/symbol_database.py
  41. 1
      python/google/protobuf/text_encoding.py
  42. 12
      python/google/protobuf/text_format.py
  43. 0
      python/google/protobuf/util/__init__.py
  44. 9
      python/setup.py
  45. 3
      python/tox.ini
  46. 17
      src/google/protobuf/any.cc
  47. 1
      src/google/protobuf/any.h
  48. 12
      src/google/protobuf/arena.cc
  49. 29
      src/google/protobuf/arena.h
  50. 4
      src/google/protobuf/arena_unittest.cc
  51. 10
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  52. 6
      src/google/protobuf/compiler/cpp/cpp_map_field.cc
  53. 2
      src/google/protobuf/compiler/cpp/cpp_message.cc
  54. 6
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  55. 2
      src/google/protobuf/compiler/java/java_map_field_lite.cc
  56. 28
      src/google/protobuf/compiler/java/java_message_lite.cc
  57. 25
      src/google/protobuf/compiler/parser.cc
  58. 4
      src/google/protobuf/compiler/parser.h
  59. 30
      src/google/protobuf/compiler/parser_unittest.cc
  60. 20
      src/google/protobuf/compiler/python/python_generator.cc
  61. 91
      src/google/protobuf/descriptor.cc
  62. 39
      src/google/protobuf/descriptor.h
  63. 317
      src/google/protobuf/descriptor.pb.cc
  64. 74
      src/google/protobuf/descriptor.pb.h
  65. 6
      src/google/protobuf/descriptor.proto
  66. 6
      src/google/protobuf/descriptor_database_unittest.cc
  67. 110
      src/google/protobuf/descriptor_unittest.cc
  68. 8
      src/google/protobuf/dynamic_message.cc
  69. 15
      src/google/protobuf/dynamic_message_unittest.cc
  70. 18
      src/google/protobuf/extension_set.cc
  71. 15
      src/google/protobuf/extension_set.h
  72. 5
      src/google/protobuf/extension_set_unittest.cc
  73. 11
      src/google/protobuf/generated_message_reflection_unittest.cc
  74. 2
      src/google/protobuf/generated_message_util.cc
  75. 6
      src/google/protobuf/io/coded_stream_unittest.cc
  76. 8
      src/google/protobuf/io/zero_copy_stream_impl_lite.h
  77. 6
      src/google/protobuf/io/zero_copy_stream_unittest.cc
  78. 3
      src/google/protobuf/map_field_inl.h
  79. 6
      src/google/protobuf/map_proto2_unittest.proto
  80. 6
      src/google/protobuf/map_test.cc
  81. 1
      src/google/protobuf/message.cc
  82. 2
      src/google/protobuf/message.h
  83. 2
      src/google/protobuf/repeated_field.h
  84. 13
      src/google/protobuf/stubs/stringpiece.h
  85. 18
      src/google/protobuf/stubs/stringpiece_unittest.cc
  86. 17
      src/google/protobuf/text_format.cc
  87. 10
      src/google/protobuf/text_format_unittest.cc
  88. 7
      src/google/protobuf/unittest_import.proto
  89. 2
      src/google/protobuf/util/field_comparator_test.cc
  90. 10
      src/google/protobuf/util/field_mask_util.cc
  91. 11
      src/google/protobuf/util/field_mask_util.h
  92. 2
      src/google/protobuf/util/internal/default_value_objectwriter.h
  93. 6
      src/google/protobuf/util/internal/json_objectwriter.cc
  94. 22
      src/google/protobuf/util/internal/protostream_objectsource.cc
  95. 4
      src/google/protobuf/util/internal/protostream_objectsource.h
  96. 41
      src/google/protobuf/util/internal/protostream_objectwriter.cc
  97. 20
      src/google/protobuf/util/internal/protostream_objectwriter.h
  98. 137
      src/google/protobuf/util/internal/protostream_objectwriter_test.cc
  99. 15
      src/google/protobuf/util/internal/utility.cc
  100. 6
      src/google/protobuf/util/internal/utility.h
  101. Some files were not shown because too many files have changed in this diff Show More

@ -508,6 +508,7 @@ python_EXTRA_DIST= \
python/google/protobuf/internal/factory_test1.proto \ python/google/protobuf/internal/factory_test1.proto \
python/google/protobuf/internal/factory_test2.proto \ python/google/protobuf/internal/factory_test2.proto \
python/google/protobuf/internal/generator_test.py \ python/google/protobuf/internal/generator_test.py \
python/google/protobuf/internal/json_format_test.py \
python/google/protobuf/internal/message_factory_test.py \ python/google/protobuf/internal/message_factory_test.py \
python/google/protobuf/internal/message_listener.py \ python/google/protobuf/internal/message_listener.py \
python/google/protobuf/internal/message_set_extensions.proto \ python/google/protobuf/internal/message_set_extensions.proto \
@ -563,6 +564,7 @@ python_EXTRA_DIST= \
python/google/protobuf/descriptor.py \ python/google/protobuf/descriptor.py \
python/google/protobuf/descriptor_database.py \ python/google/protobuf/descriptor_database.py \
python/google/protobuf/descriptor_pool.py \ python/google/protobuf/descriptor_pool.py \
python/google/protobuf/json_format.py \
python/google/protobuf/message.py \ python/google/protobuf/message.py \
python/google/protobuf/message_factory.py \ python/google/protobuf/message_factory.py \
python/google/protobuf/proto_builder.py \ python/google/protobuf/proto_builder.py \

@ -62,9 +62,8 @@ public abstract class GeneratedMessageLite<
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** For use by generated code only. */ /** For use by generated code only. Lazily initialized to reduce allocations. */
protected UnknownFieldSetLite unknownFields = protected UnknownFieldSetLite unknownFields = null;
UnknownFieldSetLite.getDefaultInstance();
/** For use by generated code only. */ /** For use by generated code only. */
protected int memoizedSerializedSize = -1; protected int memoizedSerializedSize = -1;
@ -84,19 +83,56 @@ public abstract class GeneratedMessageLite<
return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
} }
// The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
// mutable during the parsing constructor and immutable after. This allows us to avoid
// any unnecessary intermediary allocations while reducing the generated code size.
/**
* Lazily initializes unknown fields.
*/
private final void ensureUnknownFieldsInitialized() {
if (unknownFields == null) {
unknownFields = UnknownFieldSetLite.newInstance();
}
}
/** /**
* Called by subclasses to parse an unknown field. For use by generated code * Called by subclasses to parse an unknown field. For use by generated code only.
* only. *
* @return {@code true} unless the tag is an end-group tag. * @return {@code true} unless the tag is an end-group tag.
*/ */
protected static boolean parseUnknownField( protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
CodedInputStream input, ensureUnknownFieldsInitialized();
UnknownFieldSetLite.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return unknownFields.mergeFieldFrom(tag, input); return unknownFields.mergeFieldFrom(tag, input);
} }
/**
* Called by subclasses to parse an unknown field. For use by generated code only.
*/
protected void mergeVarintField(int tag, int value) {
ensureUnknownFieldsInitialized();
unknownFields.mergeVarintField(tag, value);
}
/**
* Called by subclasses to parse an unknown field. For use by generated code only.
*/
protected void mergeLengthDelimitedField(int fieldNumber, ByteString value) {
ensureUnknownFieldsInitialized();
unknownFields.mergeLengthDelimitedField(fieldNumber, value);
}
/**
* Called by subclasses to complete parsing. For use by generated code only.
*/
protected void doneParsing() {
if (unknownFields == null) {
unknownFields = UnknownFieldSetLite.getDefaultInstance();
} else {
unknownFields.makeImmutable();
}
}
public final boolean isInitialized() { public final boolean isInitialized() {
return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null; return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
} }
@ -171,7 +207,7 @@ public abstract class GeneratedMessageLite<
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) { protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) {
this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields); this.unknownFields = UnknownFieldSetLite.mutableCopyOf(this.unknownFields, unknownFields);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -225,7 +261,13 @@ public abstract class GeneratedMessageLite<
//@Override (Java 1.6 override semantics, but we must support 1.5) //@Override (Java 1.6 override semantics, but we must support 1.5)
public MessageType buildPartial() { public MessageType buildPartial() {
if (isBuilt) {
return instance;
}
instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
instance.unknownFields.makeImmutable();
isBuilt = true; isBuilt = true;
return instance; return instance;
} }
@ -249,18 +291,6 @@ public abstract class GeneratedMessageLite<
public MessageType getDefaultInstanceForType() { public MessageType getDefaultInstanceForType() {
return defaultInstance; return defaultInstance;
} }
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
CodedInputStream input,
UnknownFieldSetLite.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return unknownFields.mergeFieldFrom(tag, input);
}
public BuilderType mergeFrom( public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input, com.google.protobuf.CodedInputStream input,
@ -334,6 +364,130 @@ public abstract class GeneratedMessageLite<
extensions.mergeFrom(((ExtendableMessage) other).extensions); extensions.mergeFrom(((ExtendableMessage) other).extensions);
} }
/**
* Parse an unknown field or an extension. For use by generated code only.
*
* <p>For use by generated code only.
*
* @return {@code true} unless the tag is an end-group tag.
*/
protected <MessageType extends MessageLite> boolean parseUnknownField(
MessageType defaultInstance,
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
int wireType = WireFormat.getTagWireType(tag);
int fieldNumber = WireFormat.getTagFieldNumber(tag);
// TODO(dweis): How much bytecode would be saved by not requiring the generated code to
// provide the default instance?
GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(
defaultInstance, fieldNumber);
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 parseUnknownField(tag, input);
}
if (packed) {
int length = input.readRawVarint32();
int limit = input.pushLimit(length);
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
int rawValue = input.readEnum();
Object value =
extension.descriptor.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
extensions.addRepeatedField(extension.descriptor,
extension.singularToFieldSetType(value));
}
} else {
while (input.getBytesUntilLimit() > 0) {
Object value =
FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType(),
/*checkUtf8=*/ false);
extensions.addRepeatedField(extension.descriptor, value);
}
}
input.popLimit(limit);
} else {
Object value;
switch (extension.descriptor.getLiteJavaType()) {
case MESSAGE: {
MessageLite.Builder subBuilder = null;
if (!extension.descriptor.isRepeated()) {
MessageLite existingValue =
(MessageLite) extensions.getField(extension.descriptor);
if (existingValue != null) {
subBuilder = existingValue.toBuilder();
}
}
if (subBuilder == null) {
subBuilder = extension.getMessageDefaultInstance()
.newBuilderForType();
}
if (extension.descriptor.getLiteType() ==
WireFormat.FieldType.GROUP) {
input.readGroup(extension.getNumber(),
subBuilder, extensionRegistry);
} else {
input.readMessage(subBuilder, extensionRegistry);
}
value = subBuilder.build();
break;
}
case ENUM:
int rawValue = input.readEnum();
value = extension.descriptor.getEnumType()
.findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// write it to unknown fields object.
if (value == null) {
mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType(),
/*checkUtf8=*/ false);
break;
}
if (extension.descriptor.isRepeated()) {
extensions.addRepeatedField(extension.descriptor,
extension.singularToFieldSetType(value));
} else {
extensions.setField(extension.descriptor,
extension.singularToFieldSetType(value));
}
}
return true;
}
private void verifyExtensionContainingType( private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) { final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() != if (extension.getContainingTypeDefaultInstance() !=
@ -404,11 +558,10 @@ public abstract class GeneratedMessageLite<
} }
/** @Override
* Used by parsing constructors in generated classes. protected final void doneParsing() {
*/ super.doneParsing();
protected static void makeExtensionsImmutable(
FieldSet<ExtensionDescriptor> extensions) {
extensions.makeImmutable(); extensions.makeImmutable();
} }
@ -619,131 +772,6 @@ public abstract class GeneratedMessageLite<
} }
} }
//-----------------------------------------------------------------
/**
* Parse an unknown field or an extension. For use by generated code only.
* @return {@code true} unless the tag is an end-group tag.
*/
protected static <MessageType extends MessageLite>
boolean parseUnknownField(
FieldSet<ExtensionDescriptor> extensions,
MessageType defaultInstance,
CodedInputStream input,
UnknownFieldSetLite.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
int wireType = WireFormat.getTagWireType(tag);
int fieldNumber = WireFormat.getTagFieldNumber(tag);
GeneratedExtension<MessageType, ?> extension =
extensionRegistry.findLiteExtensionByNumber(
defaultInstance, fieldNumber);
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 unknownFields.mergeFieldFrom(tag, input);
}
if (packed) {
int length = input.readRawVarint32();
int limit = input.pushLimit(length);
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
int rawValue = input.readEnum();
Object value =
extension.descriptor.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
extensions.addRepeatedField(extension.descriptor,
extension.singularToFieldSetType(value));
}
} else {
while (input.getBytesUntilLimit() > 0) {
Object value =
FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType(),
/*checkUtf8=*/ false);
extensions.addRepeatedField(extension.descriptor, value);
}
}
input.popLimit(limit);
} else {
Object value;
switch (extension.descriptor.getLiteJavaType()) {
case MESSAGE: {
MessageLite.Builder subBuilder = null;
if (!extension.descriptor.isRepeated()) {
MessageLite existingValue =
(MessageLite) extensions.getField(extension.descriptor);
if (existingValue != null) {
subBuilder = existingValue.toBuilder();
}
}
if (subBuilder == null) {
subBuilder = extension.getMessageDefaultInstance()
.newBuilderForType();
}
if (extension.descriptor.getLiteType() ==
WireFormat.FieldType.GROUP) {
input.readGroup(extension.getNumber(),
subBuilder, extensionRegistry);
} else {
input.readMessage(subBuilder, extensionRegistry);
}
value = subBuilder.build();
break;
}
case ENUM:
int rawValue = input.readEnum();
value = extension.descriptor.getEnumType()
.findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// write it to unknown fields object.
if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType(),
/*checkUtf8=*/ false);
break;
}
if (extension.descriptor.isRepeated()) {
extensions.addRepeatedField(extension.descriptor,
extension.singularToFieldSetType(value));
} else {
extensions.setField(extension.descriptor,
extension.singularToFieldSetType(value));
}
}
return true;
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/** For use by generated code only. */ /** For use by generated code only. */
@ -893,7 +921,7 @@ public abstract class GeneratedMessageLite<
extends ExtensionLite<ContainingType, Type> { extends ExtensionLite<ContainingType, Type> {
/** /**
* Create a new isntance with the given parameters. * Create a new instance with the given parameters.
* *
* The last parameter {@code singularType} is only needed for enum types. * The last parameter {@code singularType} is only needed for enum types.
* We store integer values for enum types in a {@link ExtendableMessage} * We store integer values for enum types in a {@link ExtendableMessage}
@ -905,7 +933,7 @@ public abstract class GeneratedMessageLite<
final Type defaultValue, final Type defaultValue,
final MessageLite messageDefaultInstance, final MessageLite messageDefaultInstance,
final ExtensionDescriptor descriptor, final ExtensionDescriptor descriptor,
Class singularType) { final Class singularType) {
// Defensive checks to verify the correct initialization order of // Defensive checks to verify the correct initialization order of
// GeneratedExtensions and their related GeneratedMessages. // GeneratedExtensions and their related GeneratedMessages.
if (containingTypeDefaultInstance == null) { if (containingTypeDefaultInstance == null) {
@ -921,24 +949,12 @@ public abstract class GeneratedMessageLite<
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance; this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor; this.descriptor = descriptor;
// Use Java reflection to invoke the static method {@code valueOf} of
// enum types in order to convert integers to concrete enum objects.
this.singularType = singularType;
if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
this.enumValueOf = getMethodOrDie(
singularType, "valueOf", int.class);
} else {
this.enumValueOf = null;
}
} }
final ContainingType containingTypeDefaultInstance; final ContainingType containingTypeDefaultInstance;
final Type defaultValue; final Type defaultValue;
final MessageLite messageDefaultInstance; final MessageLite messageDefaultInstance;
final ExtensionDescriptor descriptor; final ExtensionDescriptor descriptor;
final Class singularType;
final Method enumValueOf;
/** /**
* Default instance of the type being extended, used to identify that type. * Default instance of the type being extended, used to identify that type.
@ -980,7 +996,7 @@ public abstract class GeneratedMessageLite<
Object singularFromFieldSetType(final Object value) { Object singularFromFieldSetType(final Object value) {
if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) { if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
return invokeOrDie(enumValueOf, null, (Integer) value); return descriptor.enumTypeMap.findValueByNumber((Integer) value);
} else { } else {
return value; return value;
} }

@ -118,6 +118,21 @@ public final class TextFormat {
} }
} }
/**
* Generates a human readable form of the field, useful for debugging
* and other purposes, with no newline characters.
*/
public static String shortDebugString(final FieldDescriptor field,
final Object value) {
try {
final StringBuilder sb = new StringBuilder();
SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
return sb.toString().trim();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/** /**
* Generates a human readable form of the unknown fields, useful for debugging * Generates a human readable form of the unknown fields, useful for debugging
* and other purposes, with no newline characters. * and other purposes, with no newline characters.

@ -45,12 +45,13 @@ import java.util.Arrays;
* @author dweis@google.com (Daniel Weis) * @author dweis@google.com (Daniel Weis)
*/ */
public final class UnknownFieldSetLite { public final class UnknownFieldSetLite {
private static final int[] EMPTY_INT_ARRAY = new int[0]; // Arbitrarily chosen.
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; // TODO(dweis): Tune this number?
private static final int MIN_CAPACITY = 8;
private static final UnknownFieldSetLite DEFAULT_INSTANCE = private static final UnknownFieldSetLite DEFAULT_INSTANCE =
new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY); new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */);
/** /**
* Get an empty {@code UnknownFieldSetLite}. * Get an empty {@code UnknownFieldSetLite}.
@ -62,25 +63,32 @@ public final class UnknownFieldSetLite {
} }
/** /**
* Create a new {@link Builder}. * Returns an empty {@code UnknownFieldSetLite.Builder}.
* *
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
public static Builder newBuilder() { public static Builder newBuilder() {
return new Builder(); return new Builder();
} }
/**
* Returns a new mutable instance.
*/
static UnknownFieldSetLite newInstance() {
return new UnknownFieldSetLite();
}
/** /**
* Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and
* {@code second}. * {@code second}.
*/ */
static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) { static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) {
int count = first.count + second.count; int count = first.count + second.count;
int[] tags = Arrays.copyOf(first.tags, count); int[] tags = Arrays.copyOf(first.tags, count);
System.arraycopy(second.tags, 0, tags, first.count, second.count); System.arraycopy(second.tags, 0, tags, first.count, second.count);
Object[] objects = Arrays.copyOf(first.objects, count); Object[] objects = Arrays.copyOf(first.objects, count);
System.arraycopy(second.objects, 0, objects, first.count, second.count); System.arraycopy(second.objects, 0, objects, first.count, second.count);
return new UnknownFieldSetLite(count, tags, objects); return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
} }
/** /**
@ -102,14 +110,45 @@ public final class UnknownFieldSetLite {
* The lazily computed serialized size of the set. * The lazily computed serialized size of the set.
*/ */
private int memoizedSerializedSize = -1; private int memoizedSerializedSize = -1;
/**
* Indicates that this object is mutable.
*/
private boolean isMutable;
/**
* Constructs a mutable {@code UnknownFieldSetLite}.
*/
private UnknownFieldSetLite() {
this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */);
}
/** /**
* Constructs the {@code UnknownFieldSetLite}. * Constructs the {@code UnknownFieldSetLite}.
*/ */
private UnknownFieldSetLite(int count, int[] tags, Object[] objects) { private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) {
this.count = count; this.count = count;
this.tags = tags; this.tags = tags;
this.objects = objects; this.objects = objects;
this.isMutable = isMutable;
}
/**
* Marks this object as immutable.
*
* <p>Future calls to methods that attempt to modify this object will throw.
*/
public void makeImmutable() {
this.isMutable = false;
}
/**
* Throws an {@link UnsupportedOperationException} if immutable.
*/
void checkMutable() {
if (!isMutable) {
throw new UnsupportedOperationException();
}
} }
/** /**
@ -223,6 +262,114 @@ public final class UnknownFieldSetLite {
return hashCode; return hashCode;
} }
private void storeField(int tag, Object value) {
ensureCapacity();
tags[count] = tag;
objects[count] = value;
count++;
}
/**
* Ensures that our arrays are long enough to store more metadata.
*/
private void ensureCapacity() {
if (count == tags.length) {
int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
int newLength = count + increment;
tags = Arrays.copyOf(tags, newLength);
objects = Arrays.copyOf(objects, newLength);
}
}
/**
* Parse a single field from {@code input} and merge it into this set.
*
* <p>For use by generated code only.
*
* @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an end group tag.
*/
boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
checkMutable();
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
storeField(tag, input.readInt64());
return true;
case WireFormat.WIRETYPE_FIXED32:
storeField(tag, input.readFixed32());
return true;
case WireFormat.WIRETYPE_FIXED64:
storeField(tag, input.readFixed64());
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
storeField(tag, input.readBytes());
return true;
case WireFormat.WIRETYPE_START_GROUP:
final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite();
subFieldSet.mergeFrom(input);
input.checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
storeField(tag, subFieldSet);
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Convenience method for merging a new field containing a single varint
* value. This is used in particular when an unknown enum value is
* encountered.
*
* <p>For use by generated code only.
*/
UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) {
checkMutable();
if (fieldNumber == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
return this;
}
/**
* Convenience method for merging a length-delimited field.
*
* <p>For use by generated code only.
*/
UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
checkMutable();
if (fieldNumber == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
return this;
}
/**
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException {
// Ensures initialization in mergeFieldFrom.
while (true) {
final int tag = input.readTag();
if (tag == 0 || !mergeFieldFrom(tag, input)) {
break;
}
}
return this;
}
/** /**
* Builder for {@link UnknownFieldSetLite}s. * Builder for {@link UnknownFieldSetLite}s.
* *
@ -230,53 +377,26 @@ public final class UnknownFieldSetLite {
* *
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
// TODO(dweis): Update the mutable API to no longer need this builder and delete.
public static final class Builder { public static final class Builder {
// Arbitrarily chosen.
// TODO(dweis): Tune this number?
private static final int MIN_CAPACITY = 8;
private int count = 0;
private int[] tags = EMPTY_INT_ARRAY;
private Object[] objects = EMPTY_OBJECT_ARRAY;
private boolean built; private UnknownFieldSetLite set;
/** private Builder() {
* Constructs a {@code Builder}. this.set = null;
*/ }
private Builder() {}
/** /**
* Ensures internal state is initialized for use. * Ensures internal state is initialized for use.
*/ */
private void ensureNotBuilt() { private void ensureNotBuilt() {
if (built) { if (set == null) {
throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); set = new UnknownFieldSetLite();
} }
}
private void storeField(int tag, Object value) {
ensureCapacity();
tags[count] = tag; set.checkMutable();
objects[count] = value;
count++;
} }
/**
* Ensures that our arrays are long enough to store more metadata.
*/
private void ensureCapacity() {
if (count == tags.length) {
int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
int newLength = count + increment;
tags = Arrays.copyOf(tags, newLength);
objects = Arrays.copyOf(objects, newLength);
}
}
/** /**
* Parse a single field from {@code input} and merge it into this set. * Parse a single field from {@code input} and merge it into this set.
* *
@ -285,36 +405,9 @@ public final class UnknownFieldSetLite {
* @param tag The field's tag number, which was already parsed. * @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an end group tag. * @return {@code false} if the tag is an end group tag.
*/ */
public boolean mergeFieldFrom(final int tag, final CodedInputStream input) boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
throws IOException {
ensureNotBuilt(); ensureNotBuilt();
return set.mergeFieldFrom(tag, input);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
storeField(tag, input.readInt64());
return true;
case WireFormat.WIRETYPE_FIXED32:
storeField(tag, input.readFixed32());
return true;
case WireFormat.WIRETYPE_FIXED64:
storeField(tag, input.readFixed64());
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
storeField(tag, input.readBytes());
return true;
case WireFormat.WIRETYPE_START_GROUP:
final Builder subBuilder = newBuilder();
subBuilder.mergeFrom(input);
input.checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
storeField(tag, subBuilder.build());
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} }
/** /**
@ -324,71 +417,42 @@ public final class UnknownFieldSetLite {
* *
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
public Builder mergeVarintField(int fieldNumber, int value) { Builder mergeVarintField(int fieldNumber, int value) {
if (fieldNumber == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
ensureNotBuilt(); ensureNotBuilt();
set.mergeVarintField(fieldNumber, value);
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
return this; return this;
} }
/** /**
* Convenience method for merging a length-delimited field. * Convenience method for merging a length-delimited field.
* *
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
public Builder mergeLengthDelimitedField( public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
final int fieldNumber, final ByteString value) { ensureNotBuilt();
if (fieldNumber == 0) { set.mergeLengthDelimitedField(fieldNumber, value);
throw new IllegalArgumentException("Zero is not a valid field number.");
}
ensureNotBuilt();
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
return this; return this;
} }
/**
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
private Builder mergeFrom(final CodedInputStream input) throws IOException {
// Ensures initialization in mergeFieldFrom.
while (true) {
final int tag = input.readTag();
if (tag == 0 || !mergeFieldFrom(tag, input)) {
break;
}
}
return this;
}
/** /**
* Build the {@link UnknownFieldSetLite} and return it. * Build the {@link UnknownFieldSetLite} and return it.
* *
* <p>Once {@code build()} has been called, the {@code Builder} will no * <p>Once {@code build()} has been called, the {@code Builder} will no
* longer be usable. Calling any method after {@code build()} will result * longer be usable. Calling any method after {@code build()} will result
* in undefined behavior and can cause a {@code IllegalStateException} to be * in undefined behavior and can cause an
* thrown. * {@code UnsupportedOperationException} to be thrown.
* *
* <p>For use by generated code only. * <p>For use by generated code only.
*/ */
public UnknownFieldSetLite build() { public UnknownFieldSetLite build() {
if (built) { if (set == null) {
throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
}
built = true;
if (count == 0) {
return DEFAULT_INSTANCE; return DEFAULT_INSTANCE;
} }
set.checkMutable();
set.makeImmutable();
return new UnknownFieldSetLite(count, tags, objects); return set;
} }
} }
} }

@ -360,8 +360,8 @@ final class Utf8 {
static class UnpairedSurrogateException extends IllegalArgumentException { static class UnpairedSurrogateException extends IllegalArgumentException {
private UnpairedSurrogateException(int index) { private UnpairedSurrogateException(int index, int length) {
super("Unpaired surrogate at index " + index); super("Unpaired surrogate at index " + index + " of " + length);
} }
} }
@ -417,7 +417,7 @@ final class Utf8 {
// Check that we have a well-formed surrogate pair. // Check that we have a well-formed surrogate pair.
int cp = Character.codePointAt(sequence, i); int cp = Character.codePointAt(sequence, i);
if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
throw new UnpairedSurrogateException(i); throw new UnpairedSurrogateException(i, utf16Length);
} }
i++; i++;
} }
@ -457,7 +457,7 @@ final class Utf8 {
final char low; final char low;
if (i + 1 == sequence.length() if (i + 1 == sequence.length()
|| !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
throw new UnpairedSurrogateException((i - 1)); throw new UnpairedSurrogateException((i - 1), utf16Length);
} }
int codePoint = Character.toCodePoint(c, low); int codePoint = Character.toCodePoint(c, low);
bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
@ -470,7 +470,7 @@ final class Utf8 {
if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
&& (i + 1 == sequence.length() && (i + 1 == sequence.length()
|| !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) { || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
throw new UnpairedSurrogateException(i); throw new UnpairedSurrogateException(i, utf16Length);
} }
throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
} }

@ -46,6 +46,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor;
import com.google.protobuf.test.UnittestImport; import com.google.protobuf.test.UnittestImport;
import com.google.protobuf.test.UnittestImport.ImportEnum; import com.google.protobuf.test.UnittestImport.ImportEnum;
import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
import protobuf_unittest.TestCustomOptions; import protobuf_unittest.TestCustomOptions;
import protobuf_unittest.UnittestCustomOptions; import protobuf_unittest.UnittestCustomOptions;
import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto;
@ -115,7 +116,8 @@ public class DescriptorsTest extends TestCase {
assertEquals(enumType, file.findEnumTypeByName("ForeignEnum")); assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
assertNull(file.findEnumTypeByName("NoSuchType")); assertNull(file.findEnumTypeByName("NoSuchType"));
assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")); assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
assertEquals(Arrays.asList(ImportEnum.getDescriptor()), assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
ImportEnumForMap.getDescriptor()),
UnittestImport.getDescriptor().getEnumTypes()); UnittestImport.getDescriptor().getEnumTypes());
for (int i = 0; i < file.getEnumTypes().size(); i++) { for (int i = 0; i < file.getEnumTypes().size(); i++) {
assertEquals(i, file.getEnumTypes().get(i).getIndex()); assertEquals(i, file.getEnumTypes().get(i).getIndex());

@ -830,6 +830,22 @@ public class TextFormatTest extends TestCase {
.build())); .build()));
} }
public void testShortDebugString_field() {
final FieldDescriptor dataField =
OneString.getDescriptor().findFieldByName("data");
assertEquals(
"data: \"test data\"",
TextFormat.shortDebugString(dataField, "test data"));
final FieldDescriptor optionalField =
TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
final Object value = NestedMessage.newBuilder().setBb(42).build();
assertEquals(
"optional_nested_message { bb: 42 }",
TextFormat.shortDebugString(optionalField, value));
}
public void testShortDebugString_unknown() { public void testShortDebugString_unknown() {
assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }" assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+ " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:" + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"

@ -30,6 +30,8 @@
package com.google.protobuf; package com.google.protobuf;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
@ -52,7 +54,40 @@ public class UnknownFieldSetLiteTest extends TestCase {
UnknownFieldSetLite.newBuilder() UnknownFieldSetLite.newBuilder()
.build()); .build());
} }
public void testBuilderReuse() throws IOException {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
builder.mergeVarintField(10, 2);
builder.build();
try {
builder.build();
fail();
} catch (UnsupportedOperationException e) {
// Expected.
}
try {
builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
fail();
} catch (UnsupportedOperationException e) {
// Expected.
}
try {
builder.mergeVarintField(5, 1);
fail();
} catch (UnsupportedOperationException e) {
// Expected.
}
}
public void testBuilderReuse_empty() {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
builder.build();
builder.build();
}
public void testDefaultInstance() { public void testDefaultInstance() {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
@ -67,10 +102,10 @@ public class UnknownFieldSetLiteTest extends TestCase {
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
builder.mergeFieldFrom(input.readTag(), input); instance.mergeFieldFrom(input.readTag(), input);
assertEquals(foo.toByteString(), toByteString(builder.build())); assertEquals(foo.toByteString(), toByteString(instance));
} }
public void testSerializedSize() throws IOException { public void testSerializedSize() throws IOException {
@ -80,18 +115,18 @@ public class UnknownFieldSetLiteTest extends TestCase {
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
builder.mergeFieldFrom(input.readTag(), input); instance.mergeFieldFrom(input.readTag(), input);
assertEquals(foo.toByteString().size(), builder.build().getSerializedSize()); assertEquals(foo.toByteString().size(), instance.getSerializedSize());
} }
public void testMergeVarintField() throws IOException { public void testMergeVarintField() throws IOException {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
builder.mergeVarintField(10, 2); unknownFields.mergeVarintField(10, 2);
CodedInputStream input = CodedInputStream input =
CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
int tag = input.readTag(); int tag = input.readTag();
assertEquals(10, WireFormat.getTagFieldNumber(tag)); assertEquals(10, WireFormat.getTagFieldNumber(tag));
@ -101,11 +136,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
} }
public void testMergeVarintField_negative() throws IOException { public void testMergeVarintField_negative() throws IOException {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance();
builder.mergeVarintField(10, -6); builder.mergeVarintField(10, -6);
CodedInputStream input = CodedInputStream input =
CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); CodedInputStream.newInstance(toByteString(builder).toByteArray());
int tag = input.readTag(); int tag = input.readTag();
assertEquals(10, WireFormat.getTagFieldNumber(tag)); assertEquals(10, WireFormat.getTagFieldNumber(tag));
@ -115,13 +150,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
} }
public void testEqualsAndHashCode() { public void testEqualsAndHashCode() {
UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance();
builder1.mergeVarintField(10, 2); unknownFields1.mergeVarintField(10, 2);
UnknownFieldSetLite unknownFields1 = builder1.build();
UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance();
builder2.mergeVarintField(10, 2); unknownFields2.mergeVarintField(10, 2);
UnknownFieldSetLite unknownFields2 = builder2.build();
assertEquals(unknownFields1, unknownFields2); assertEquals(unknownFields1, unknownFields2);
assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode()); assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode());
@ -129,12 +162,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode()); assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode());
} }
public void testConcat() throws IOException { public void testMutableCopyOf() throws IOException {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
builder.mergeVarintField(10, 2); unknownFields.mergeVarintField(10, 2);
UnknownFieldSetLite unknownFields = builder.build(); unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields);
unknownFields.checkMutable();
unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields);
CodedInputStream input = CodedInputStream input =
CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
@ -151,53 +183,15 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertTrue(input.isAtEnd()); assertTrue(input.isAtEnd());
} }
public void testConcat_empty() { public void testMutableCopyOf_empty() {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat( UnknownFieldSetLite unknownFields = UnknownFieldSetLite.mutableCopyOf(
UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance());
unknownFields.checkMutable();
assertEquals(0, unknownFields.getSerializedSize()); assertEquals(0, unknownFields.getSerializedSize());
assertEquals(ByteString.EMPTY, toByteString(unknownFields)); assertEquals(ByteString.EMPTY, toByteString(unknownFields));
} }
public void testBuilderReuse() throws IOException {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
builder.mergeVarintField(10, 2);
builder.build();
try {
builder.build();
fail();
} catch (IllegalStateException e) {
// Expected.
}
try {
builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
fail();
} catch (IllegalStateException e) {
// Expected.
}
try {
builder.mergeVarintField(5, 1);
fail();
} catch (IllegalStateException e) {
// Expected.
}
}
public void testBuilderReuse_empty() {
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
builder.build();
try {
builder.build();
fail();
} catch (IllegalStateException e) {
// Expected.
}
}
public void testRoundTrips() throws InvalidProtocolBufferException { public void testRoundTrips() throws InvalidProtocolBufferException {
Foo foo = Foo.newBuilder() Foo foo = Foo.newBuilder()
.setValue(1) .setValue(1)
@ -301,6 +295,64 @@ public class UnknownFieldSetLiteTest extends TestCase {
// Expected. // Expected.
} }
} }
public void testMakeImmutable() throws Exception {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
unknownFields.makeImmutable();
try {
unknownFields.mergeVarintField(1, 1);
fail();
} catch (UnsupportedOperationException expected) {}
try {
unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello"));
fail();
} catch (UnsupportedOperationException expected) {}
try {
unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0]));
fail();
} catch (UnsupportedOperationException expected) {}
}
public void testEndToEnd() throws Exception {
TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance();
try {
testAllTypes.unknownFields.checkMutable();
fail();
} catch (UnsupportedOperationException expected) {}
testAllTypes = TestAllTypesLite.parseFrom(new byte[0]);
try {
testAllTypes.unknownFields.checkMutable();
fail();
} catch (UnsupportedOperationException expected) {}
testAllTypes = TestAllTypesLite.newBuilder().build();
try {
testAllTypes.unknownFields.checkMutable();
fail();
} catch (UnsupportedOperationException expected) {}
testAllTypes = TestAllTypesLite.newBuilder()
.setDefaultBool(true)
.build();
try {
testAllTypes.unknownFields.checkMutable();
fail();
} catch (UnsupportedOperationException expected) {}
TestAllExtensionsLite testAllExtensions = TestAllExtensionsLite.newBuilder()
.mergeFrom(TestAllExtensionsLite.newBuilder()
.setExtension(UnittestLite.optionalInt32ExtensionLite, 2)
.build().toByteArray())
.build();
try {
testAllExtensions.unknownFields.checkMutable();
fail();
} catch (UnsupportedOperationException expected) {}
}
private ByteString toByteString(UnknownFieldSetLite unknownFields) { private ByteString toByteString(UnknownFieldSetLite unknownFields) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

@ -140,11 +140,11 @@ message TestConflictingFieldNames {
optional bytes bytes_field_count = 14; optional bytes bytes_field_count = 14;
optional TestMessage message_field_count = 15; optional TestMessage message_field_count = 15;
repeated int32 Int32Field = 21; repeated int32 Int32Field = 21; // NO_PROTO3
repeated TestEnum EnumField = 22; repeated TestEnum EnumField = 22; // NO_PROTO3
repeated string StringField = 23; repeated string StringField = 23; // NO_PROTO3
repeated bytes BytesField = 24; repeated bytes BytesField = 24; // NO_PROTO3
repeated TestMessage MessageField = 25; repeated TestMessage MessageField = 25; // NO_PROTO3
// This field conflicts with "int32_field" as they both generate // This field conflicts with "int32_field" as they both generate
// the method getInt32FieldList(). // the method getInt32FieldList().

@ -344,6 +344,7 @@ typedef GPB_ENUM(GPBFieldDescriptorProto_FieldNumber) {
GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7, GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7,
GPBFieldDescriptorProto_FieldNumber_Options = 8, GPBFieldDescriptorProto_FieldNumber_Options = 8,
GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9, GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9,
GPBFieldDescriptorProto_FieldNumber_JsonName = 10,
}; };
// Describes a field within a message. // Describes a field within a message.
@ -389,6 +390,13 @@ typedef GPB_ENUM(GPBFieldDescriptorProto_FieldNumber) {
@property(nonatomic, readwrite) BOOL hasOneofIndex; @property(nonatomic, readwrite) BOOL hasOneofIndex;
@property(nonatomic, readwrite) int32_t oneofIndex; @property(nonatomic, readwrite) int32_t oneofIndex;
// JSON name of this field. The value is set by protocol compiler. If the
// user has set a "json_name" option on this field, that option's value
// will be used. Otherwise, it's deduced from the field's name by converting
// it to camelCase.
@property(nonatomic, readwrite) BOOL hasJsonName;
@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName;
@property(nonatomic, readwrite) BOOL hasOptions; @property(nonatomic, readwrite) BOOL hasOptions;
@property(nonatomic, readwrite, strong, null_resettable) GPBFieldOptions *options; @property(nonatomic, readwrite, strong, null_resettable) GPBFieldOptions *options;

@ -578,6 +578,7 @@ typedef struct GPBDescriptorProto_ReservedRange__storage_ {
@dynamic hasExtendee, extendee; @dynamic hasExtendee, extendee;
@dynamic hasDefaultValue, defaultValue; @dynamic hasDefaultValue, defaultValue;
@dynamic hasOneofIndex, oneofIndex; @dynamic hasOneofIndex, oneofIndex;
@dynamic hasJsonName, jsonName;
@dynamic hasOptions, options; @dynamic hasOptions, options;
typedef struct GPBFieldDescriptorProto__storage_ { typedef struct GPBFieldDescriptorProto__storage_ {
@ -591,6 +592,7 @@ typedef struct GPBFieldDescriptorProto__storage_ {
NSString *typeName; NSString *typeName;
NSString *defaultValue; NSString *defaultValue;
GPBFieldOptions *options; GPBFieldOptions *options;
NSString *jsonName;
} GPBFieldDescriptorProto__storage_; } GPBFieldDescriptorProto__storage_;
// This method is threadsafe because it is initially called // This method is threadsafe because it is initially called
@ -679,7 +681,7 @@ typedef struct GPBFieldDescriptorProto__storage_ {
{ {
.name = "options", .name = "options",
.number = GPBFieldDescriptorProto_FieldNumber_Options, .number = GPBFieldDescriptorProto_FieldNumber_Options,
.hasIndex = 8, .hasIndex = 9,
.flags = GPBFieldOptional, .flags = GPBFieldOptional,
.dataType = GPBDataTypeMessage, .dataType = GPBDataTypeMessage,
.offset = offsetof(GPBFieldDescriptorProto__storage_, options), .offset = offsetof(GPBFieldDescriptorProto__storage_, options),
@ -698,6 +700,17 @@ typedef struct GPBFieldDescriptorProto__storage_ {
.dataTypeSpecific.className = NULL, .dataTypeSpecific.className = NULL,
.fieldOptions = NULL, .fieldOptions = NULL,
}, },
{
.name = "jsonName",
.number = GPBFieldDescriptorProto_FieldNumber_JsonName,
.hasIndex = 8,
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
.offset = offsetof(GPBFieldDescriptorProto__storage_, jsonName),
.defaultValue.valueString = nil,
.dataTypeSpecific.className = NULL,
.fieldOptions = NULL,
},
}; };
static GPBMessageEnumDescription enums[] = { static GPBMessageEnumDescription enums[] = {
{ .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor }, { .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor },

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2007 Google Inc. All Rights Reserved.
"""Descriptors essentially contain exactly the information found in a .proto """Descriptors essentially contain exactly the information found in a .proto
file, in types that make this information accessible in Python. file, in types that make this information accessible in Python.
""" """
@ -40,7 +38,6 @@ import six
from google.protobuf.internal import api_implementation from google.protobuf.internal import api_implementation
_USE_C_DESCRIPTORS = False _USE_C_DESCRIPTORS = False
if api_implementation.Type() == 'cpp': if api_implementation.Type() == 'cpp':
# Used by MakeDescriptor in cpp mode # Used by MakeDescriptor in cpp mode
@ -221,6 +218,9 @@ class Descriptor(_NestedDescriptorBase):
fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
objects as in |fields|, but indexed by "name" attribute in each objects as in |fields|, but indexed by "name" attribute in each
FieldDescriptor. FieldDescriptor.
fields_by_camelcase_name: (dict str -> FieldDescriptor) Same
FieldDescriptor objects as in |fields|, but indexed by
"camelcase_name" attribute in each FieldDescriptor.
nested_types: (list of Descriptors) Descriptor references nested_types: (list of Descriptors) Descriptor references
for all protocol message types nested within this one. for all protocol message types nested within this one.
@ -292,6 +292,7 @@ class Descriptor(_NestedDescriptorBase):
field.containing_type = self field.containing_type = self
self.fields_by_number = dict((f.number, f) for f in fields) self.fields_by_number = dict((f.number, f) for f in fields)
self.fields_by_name = dict((f.name, f) for f in fields) self.fields_by_name = dict((f.name, f) for f in fields)
self._fields_by_camelcase_name = None
self.nested_types = nested_types self.nested_types = nested_types
for nested_type in nested_types: for nested_type in nested_types:
@ -317,6 +318,13 @@ class Descriptor(_NestedDescriptorBase):
oneof.containing_type = self oneof.containing_type = self
self.syntax = syntax or "proto2" self.syntax = syntax or "proto2"
@property
def fields_by_camelcase_name(self):
if self._fields_by_camelcase_name is None:
self._fields_by_camelcase_name = dict(
(f.camelcase_name, f) for f in self.fields)
return self._fields_by_camelcase_name
def EnumValueName(self, enum, value): def EnumValueName(self, enum, value):
"""Returns the string name of an enum value. """Returns the string name of an enum value.
@ -365,6 +373,7 @@ class FieldDescriptor(DescriptorBase):
name: (str) Name of this field, exactly as it appears in .proto. name: (str) Name of this field, exactly as it appears in .proto.
full_name: (str) Name of this field, including containing scope. This is full_name: (str) Name of this field, including containing scope. This is
particularly relevant for extensions. particularly relevant for extensions.
camelcase_name: (str) Camelcase name of this field.
index: (int) Dense, 0-indexed index giving the order that this index: (int) Dense, 0-indexed index giving the order that this
field textually appears within its message in the .proto file. field textually appears within its message in the .proto file.
number: (int) Tag number declared for this field in the .proto file. number: (int) Tag number declared for this field in the .proto file.
@ -509,6 +518,7 @@ class FieldDescriptor(DescriptorBase):
super(FieldDescriptor, self).__init__(options, 'FieldOptions') super(FieldDescriptor, self).__init__(options, 'FieldOptions')
self.name = name self.name = name
self.full_name = full_name self.full_name = full_name
self._camelcase_name = None
self.index = index self.index = index
self.number = number self.number = number
self.type = type self.type = type
@ -530,6 +540,12 @@ class FieldDescriptor(DescriptorBase):
else: else:
self._cdescriptor = None self._cdescriptor = None
@property
def camelcase_name(self):
if self._camelcase_name is None:
self._camelcase_name = _ToCamelCase(self.name)
return self._camelcase_name
@staticmethod @staticmethod
def ProtoTypeToCppProtoType(proto_type): def ProtoTypeToCppProtoType(proto_type):
"""Converts from a Python proto type to a C++ Proto Type. """Converts from a Python proto type to a C++ Proto Type.
@ -822,6 +838,27 @@ def _ParseOptions(message, string):
return message return message
def _ToCamelCase(name):
"""Converts name to camel-case and returns it."""
capitalize_next = False
result = []
for c in name:
if c == '_':
if result:
capitalize_next = True
elif capitalize_next:
result.append(c.upper())
capitalize_next = False
else:
result += c
# Lower-case the first letter.
if result and result[0].isupper():
result[0] = result[0].lower()
return ''.join(result)
def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True, def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
syntax=None): syntax=None):
"""Make a protobuf Descriptor given a DescriptorProto protobuf. """Make a protobuf Descriptor given a DescriptorProto protobuf.

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2009 Google Inc. All Rights Reserved.
"""Code for decoding protocol buffer primitives. """Code for decoding protocol buffer primitives.
This code is very similar to encoder.py -- read the docs for that module first. This code is very similar to encoder.py -- read the docs for that module first.

@ -35,11 +35,11 @@
__author__ = 'matthewtoia@google.com (Matt Toia)' __author__ = 'matthewtoia@google.com (Matt Toia)'
import os import os
try: try:
import unittest2 as unittest import unittest2 as unittest
except ImportError: except ImportError:
import unittest import unittest
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pb2
from google.protobuf.internal import api_implementation from google.protobuf.internal import api_implementation
@ -47,6 +47,7 @@ from google.protobuf.internal import descriptor_pool_test1_pb2
from google.protobuf.internal import descriptor_pool_test2_pb2 from google.protobuf.internal import descriptor_pool_test2_pb2
from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test1_pb2
from google.protobuf.internal import factory_test2_pb2 from google.protobuf.internal import factory_test2_pb2
from google.protobuf.internal import test_util
from google.protobuf import descriptor from google.protobuf import descriptor
from google.protobuf import descriptor_database from google.protobuf import descriptor_database
from google.protobuf import descriptor_pool from google.protobuf import descriptor_pool

@ -1,4 +1,4 @@
#! /usr/bin/python #! /usr/bin/env python
# #
# Protocol Buffers - Google's data interchange format # Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved. # Copyright 2008 Google Inc. All rights reserved.
@ -36,20 +36,20 @@ __author__ = 'robinson@google.com (Will Robinson)'
import sys import sys
try:
import unittest2 as unittest
except ImportError:
import unittest
from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pb2
from google.protobuf.internal import api_implementation from google.protobuf.internal import api_implementation
from google.protobuf.internal import test_util
from google.protobuf import descriptor from google.protobuf import descriptor
from google.protobuf import symbol_database from google.protobuf import symbol_database
from google.protobuf import text_format from google.protobuf import text_format
try:
import unittest2 as unittest
except ImportError:
import unittest
TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """ TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """
name: 'TestEmptyMessage' name: 'TestEmptyMessage'
@ -425,10 +425,12 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.CheckDescriptorSequence(message_descriptor.fields) self.CheckDescriptorSequence(message_descriptor.fields)
self.CheckDescriptorMapping(message_descriptor.fields_by_name) self.CheckDescriptorMapping(message_descriptor.fields_by_name)
self.CheckDescriptorMapping(message_descriptor.fields_by_number) self.CheckDescriptorMapping(message_descriptor.fields_by_number)
self.CheckDescriptorMapping(message_descriptor.fields_by_camelcase_name)
def CheckFieldDescriptor(self, field_descriptor): def CheckFieldDescriptor(self, field_descriptor):
# Basic properties # Basic properties
self.assertEqual(field_descriptor.name, 'optional_int32') self.assertEqual(field_descriptor.name, 'optional_int32')
self.assertEqual(field_descriptor.camelcase_name, 'optionalInt32')
self.assertEqual(field_descriptor.full_name, self.assertEqual(field_descriptor.full_name,
'protobuf_unittest.TestAllTypes.optional_int32') 'protobuf_unittest.TestAllTypes.optional_int32')
self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes') self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes')
@ -437,6 +439,10 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
field_descriptor.containing_type.fields_by_name['optional_int32'], field_descriptor.containing_type.fields_by_name['optional_int32'],
field_descriptor) field_descriptor)
self.assertEqual(
field_descriptor.containing_type.fields_by_camelcase_name[
'optionalInt32'],
field_descriptor)
self.assertIn(field_descriptor, [field_descriptor]) self.assertIn(field_descriptor, [field_descriptor])
self.assertIn(field_descriptor, {field_descriptor: None}) self.assertIn(field_descriptor, {field_descriptor: None})
@ -481,6 +487,9 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.CheckMessageDescriptor(message_descriptor) self.CheckMessageDescriptor(message_descriptor)
field_descriptor = message_descriptor.fields_by_name['optional_int32'] field_descriptor = message_descriptor.fields_by_name['optional_int32']
self.CheckFieldDescriptor(field_descriptor) self.CheckFieldDescriptor(field_descriptor)
field_descriptor = message_descriptor.fields_by_camelcase_name[
'optionalInt32']
self.CheckFieldDescriptor(field_descriptor)
def testCppDescriptorContainer(self): def testCppDescriptorContainer(self):
# Check that the collection is still valid even if the parent disappeared. # Check that the collection is still valid even if the parent disappeared.
@ -779,5 +788,20 @@ class MakeDescriptorTest(unittest.TestCase):
self.assertEqual(101, self.assertEqual(101,
options.Extensions[unittest_custom_options_pb2.msgopt].i) options.Extensions[unittest_custom_options_pb2.msgopt].i)
def testCamelcaseName(self):
descriptor_proto = descriptor_pb2.DescriptorProto()
descriptor_proto.name = 'Bar'
names = ['foo_foo', 'FooBar', 'fooBaz', 'fooFoo', 'foobar']
camelcase_names = ['fooFoo', 'fooBar', 'fooBaz', 'fooFoo', 'foobar']
for index in range(len(names)):
field = descriptor_proto.field.add()
field.number = index + 1
field.name = names[index]
result = descriptor.MakeDescriptor(descriptor_proto)
for index in range(len(camelcase_names)):
self.assertEqual(result.fields[index].camelcase_name,
camelcase_names[index])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2009 Google Inc. All Rights Reserved.
"""Code for encoding protocol message primitives. """Code for encoding protocol message primitives.
Contains the logic for encoding every logical protocol field type Contains the logic for encoding every logical protocol field type

@ -0,0 +1,525 @@
#! /usr/bin/env python
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
# https://developers.google.com/protocol-buffers/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Test for google.protobuf.json_format."""
__author__ = 'jieluo@google.com (Jie Luo)'
import json
import math
import sys
try:
import unittest2 as unittest
except ImportError:
import unittest
from google.protobuf import json_format
from google.protobuf.util import json_format_proto3_pb2
class JsonFormatBase(unittest.TestCase):
def FillAllFields(self, message):
message.int32_value = 20
message.int64_value = -20
message.uint32_value = 3120987654
message.uint64_value = 12345678900
message.float_value = float('-inf')
message.double_value = 3.1415
message.bool_value = True
message.string_value = 'foo'
message.bytes_value = b'bar'
message.message_value.value = 10
message.enum_value = json_format_proto3_pb2.BAR
# Repeated
message.repeated_int32_value.append(0x7FFFFFFF)
message.repeated_int32_value.append(-2147483648)
message.repeated_int64_value.append(9007199254740992)
message.repeated_int64_value.append(-9007199254740992)
message.repeated_uint32_value.append(0xFFFFFFF)
message.repeated_uint32_value.append(0x7FFFFFF)
message.repeated_uint64_value.append(9007199254740992)
message.repeated_uint64_value.append(9007199254740991)
message.repeated_float_value.append(0)
message.repeated_double_value.append(1E-15)
message.repeated_double_value.append(float('inf'))
message.repeated_bool_value.append(True)
message.repeated_bool_value.append(False)
message.repeated_string_value.append('Few symbols!#$,;')
message.repeated_string_value.append('bar')
message.repeated_bytes_value.append(b'foo')
message.repeated_bytes_value.append(b'bar')
message.repeated_message_value.add().value = 10
message.repeated_message_value.add().value = 11
message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
self.message = message
def CheckParseBack(self, message, parsed_message):
json_format.Parse(json_format.MessageToJson(message),
parsed_message)
self.assertEqual(message, parsed_message)
def CheckError(self, text, error_message):
message = json_format_proto3_pb2.TestMessage()
self.assertRaisesRegexp(
json_format.ParseError,
error_message,
json_format.Parse, text, message)
class JsonFormatTest(JsonFormatBase):
def testEmptyMessageToJson(self):
message = json_format_proto3_pb2.TestMessage()
self.assertEqual(json_format.MessageToJson(message),
'{}')
parsed_message = json_format_proto3_pb2.TestMessage()
self.CheckParseBack(message, parsed_message)
def testPartialMessageToJson(self):
message = json_format_proto3_pb2.TestMessage(
string_value='test',
repeated_int32_value=[89, 4])
self.assertEqual(json.loads(json_format.MessageToJson(message)),
json.loads('{"stringValue": "test", '
'"repeatedInt32Value": [89, 4]}'))
parsed_message = json_format_proto3_pb2.TestMessage()
self.CheckParseBack(message, parsed_message)
def testAllFieldsToJson(self):
message = json_format_proto3_pb2.TestMessage()
text = ('{"int32Value": 20, '
'"int64Value": "-20", '
'"uint32Value": 3120987654,'
'"uint64Value": "12345678900",'
'"floatValue": "-Infinity",'
'"doubleValue": 3.1415,'
'"boolValue": true,'
'"stringValue": "foo",'
'"bytesValue": "YmFy",'
'"messageValue": {"value": 10},'
'"enumValue": "BAR",'
'"repeatedInt32Value": [2147483647, -2147483648],'
'"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
'"repeatedUint32Value": [268435455, 134217727],'
'"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
'"repeatedFloatValue": [0],'
'"repeatedDoubleValue": [1e-15, "Infinity"],'
'"repeatedBoolValue": [true, false],'
'"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
'"repeatedBytesValue": ["Zm9v", "YmFy"],'
'"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
'"repeatedEnumValue": ["FOO", "BAR"]'
'}')
self.FillAllFields(message)
self.assertEqual(
json.loads(json_format.MessageToJson(message)),
json.loads(text))
parsed_message = json_format_proto3_pb2.TestMessage()
json_format.Parse(text, parsed_message)
self.assertEqual(message, parsed_message)
def testJsonEscapeString(self):
message = json_format_proto3_pb2.TestMessage()
if sys.version_info[0] < 3:
message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
else:
message.string_value = '&\n<\"\r>\b\t\f\\\001/'
message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
self.assertEqual(
json_format.MessageToJson(message),
'{\n "stringValue": '
'"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
parsed_message = json_format_proto3_pb2.TestMessage()
self.CheckParseBack(message, parsed_message)
text = u'{"int32Value": "\u0031"}'
json_format.Parse(text, message)
self.assertEqual(message.int32_value, 1)
def testAlwaysSeriliaze(self):
message = json_format_proto3_pb2.TestMessage(
string_value='foo')
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{'
'"repeatedStringValue": [],'
'"stringValue": "foo",'
'"repeatedBoolValue": [],'
'"repeatedUint32Value": [],'
'"repeatedInt32Value": [],'
'"enumValue": "FOO",'
'"int32Value": 0,'
'"floatValue": 0,'
'"int64Value": "0",'
'"uint32Value": 0,'
'"repeatedBytesValue": [],'
'"repeatedUint64Value": [],'
'"repeatedDoubleValue": [],'
'"bytesValue": "",'
'"boolValue": false,'
'"repeatedEnumValue": [],'
'"uint64Value": "0",'
'"doubleValue": 0,'
'"repeatedFloatValue": [],'
'"repeatedInt64Value": [],'
'"repeatedMessageValue": []}'))
parsed_message = json_format_proto3_pb2.TestMessage()
self.CheckParseBack(message, parsed_message)
def testMapFields(self):
message = json_format_proto3_pb2.TestMap()
message.bool_map[True] = 1
message.bool_map[False] = 2
message.int32_map[1] = 2
message.int32_map[2] = 3
message.int64_map[1] = 2
message.int64_map[2] = 3
message.uint32_map[1] = 2
message.uint32_map[2] = 3
message.uint64_map[1] = 2
message.uint64_map[2] = 3
message.string_map['1'] = 2
message.string_map['null'] = 3
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{'
'"boolMap": {"false": 2, "true": 1},'
'"int32Map": {"1": 2, "2": 3},'
'"int64Map": {"1": 2, "2": 3},'
'"uint32Map": {"1": 2, "2": 3},'
'"uint64Map": {"1": 2, "2": 3},'
'"stringMap": {"1": 2, "null": 3}'
'}'))
parsed_message = json_format_proto3_pb2.TestMap()
self.CheckParseBack(message, parsed_message)
def testOneofFields(self):
message = json_format_proto3_pb2.TestOneof()
# Always print does not affect oneof fields.
self.assertEqual(
json_format.MessageToJson(message, True),
'{}')
message.oneof_int32_value = 0
self.assertEqual(
json_format.MessageToJson(message, True),
'{\n'
' "oneofInt32Value": 0\n'
'}')
parsed_message = json_format_proto3_pb2.TestOneof()
self.CheckParseBack(message, parsed_message)
def testTimestampMessage(self):
message = json_format_proto3_pb2.TestTimestamp()
message.value.seconds = 0
message.value.nanos = 0
message.repeated_value.add().seconds = 20
message.repeated_value[0].nanos = 1
message.repeated_value.add().seconds = 0
message.repeated_value[1].nanos = 10000
message.repeated_value.add().seconds = 100000000
message.repeated_value[2].nanos = 0
# Maximum time
message.repeated_value.add().seconds = 253402300799
message.repeated_value[3].nanos = 999999999
# Minimum time
message.repeated_value.add().seconds = -62135596800
message.repeated_value[4].nanos = 0
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{'
'"value": "1970-01-01T00:00:00Z",'
'"repeatedValue": ['
' "1970-01-01T00:00:20.000000001Z",'
' "1970-01-01T00:00:00.000010Z",'
' "1973-03-03T09:46:40Z",'
' "9999-12-31T23:59:59.999999999Z",'
' "0001-01-01T00:00:00Z"'
']'
'}'))
parsed_message = json_format_proto3_pb2.TestTimestamp()
self.CheckParseBack(message, parsed_message)
text = (r'{"value": "1972-01-01T01:00:00.01+08:00",'
r'"repeatedValue":['
r' "1972-01-01T01:00:00.01+08:30",'
r' "1972-01-01T01:00:00.01-01:23"]}')
json_format.Parse(text, parsed_message)
self.assertEqual(parsed_message.value.seconds, 63104400)
self.assertEqual(parsed_message.value.nanos, 10000000)
self.assertEqual(parsed_message.repeated_value[0].seconds, 63106200)
self.assertEqual(parsed_message.repeated_value[1].seconds, 63070620)
def testDurationMessage(self):
message = json_format_proto3_pb2.TestDuration()
message.value.seconds = 1
message.repeated_value.add().seconds = 0
message.repeated_value[0].nanos = 10
message.repeated_value.add().seconds = -1
message.repeated_value[1].nanos = -1000
message.repeated_value.add().seconds = 10
message.repeated_value[2].nanos = 11000000
message.repeated_value.add().seconds = -315576000000
message.repeated_value.add().seconds = 315576000000
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{'
'"value": "1s",'
'"repeatedValue": ['
' "0.000000010s",'
' "-1.000001s",'
' "10.011s",'
' "-315576000000s",'
' "315576000000s"'
']'
'}'))
parsed_message = json_format_proto3_pb2.TestDuration()
self.CheckParseBack(message, parsed_message)
def testFieldMaskMessage(self):
message = json_format_proto3_pb2.TestFieldMask()
message.value.paths.append('foo.bar')
message.value.paths.append('bar')
self.assertEqual(
json_format.MessageToJson(message, True),
'{\n'
' "value": "foo.bar,bar"\n'
'}')
parsed_message = json_format_proto3_pb2.TestFieldMask()
self.CheckParseBack(message, parsed_message)
def testWrapperMessage(self):
message = json_format_proto3_pb2.TestWrapper()
message.bool_value.value = False
message.int32_value.value = 0
message.string_value.value = ''
message.bytes_value.value = b''
message.repeated_bool_value.add().value = True
message.repeated_bool_value.add().value = False
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{\n'
' "int32Value": 0,'
' "boolValue": false,'
' "stringValue": "",'
' "bytesValue": "",'
' "repeatedBoolValue": [true, false],'
' "repeatedInt32Value": [],'
' "repeatedUint32Value": [],'
' "repeatedFloatValue": [],'
' "repeatedDoubleValue": [],'
' "repeatedBytesValue": [],'
' "repeatedInt64Value": [],'
' "repeatedUint64Value": [],'
' "repeatedStringValue": []'
'}'))
parsed_message = json_format_proto3_pb2.TestWrapper()
self.CheckParseBack(message, parsed_message)
def testParseNull(self):
message = json_format_proto3_pb2.TestMessage()
message.repeated_int32_value.append(1)
message.repeated_int32_value.append(2)
message.repeated_int32_value.append(3)
parsed_message = json_format_proto3_pb2.TestMessage()
self.FillAllFields(parsed_message)
json_format.Parse('{"int32Value": null, '
'"int64Value": null, '
'"uint32Value": null,'
'"uint64Value": null,'
'"floatValue": null,'
'"doubleValue": null,'
'"boolValue": null,'
'"stringValue": null,'
'"bytesValue": null,'
'"messageValue": null,'
'"enumValue": null,'
'"repeatedInt32Value": [1, 2, null, 3],'
'"repeatedInt64Value": null,'
'"repeatedUint32Value": null,'
'"repeatedUint64Value": null,'
'"repeatedFloatValue": null,'
'"repeatedDoubleValue": null,'
'"repeatedBoolValue": null,'
'"repeatedStringValue": null,'
'"repeatedBytesValue": null,'
'"repeatedMessageValue": null,'
'"repeatedEnumValue": null'
'}',
parsed_message)
self.assertEqual(message, parsed_message)
def testNanFloat(self):
message = json_format_proto3_pb2.TestMessage()
message.float_value = float('nan')
text = '{\n "floatValue": "NaN"\n}'
self.assertEqual(json_format.MessageToJson(message), text)
parsed_message = json_format_proto3_pb2.TestMessage()
json_format.Parse(text, parsed_message)
self.assertTrue(math.isnan(parsed_message.float_value))
def testParseEmptyText(self):
self.CheckError('',
r'Failed to load JSON: (Expecting value)|(No JSON)')
def testParseBadEnumValue(self):
self.CheckError(
'{"enumValue": 1}',
'Enum value must be a string literal with double quotes. '
'Type "proto3.EnumType" has no value named 1.')
self.CheckError(
'{"enumValue": "baz"}',
'Enum value must be a string literal with double quotes. '
'Type "proto3.EnumType" has no value named baz.')
def testParseBadIdentifer(self):
self.CheckError('{int32Value: 1}',
(r'Failed to load JSON: Expecting property name'
r'( enclosed in double quotes)?: line 1'))
self.CheckError('{"unknownName": 1}',
'Message type "proto3.TestMessage" has no field named '
'"unknownName".')
def testDuplicateField(self):
self.CheckError('{"int32Value": 1,\n"int32Value":2}',
'Failed to load JSON: duplicate key int32Value')
def testInvalidBoolValue(self):
self.CheckError('{"boolValue": 1}',
'Failed to parse boolValue field: '
'Expected true or false without quotes.')
self.CheckError('{"boolValue": "true"}',
'Failed to parse boolValue field: '
'Expected true or false without quotes.')
def testInvalidIntegerValue(self):
message = json_format_proto3_pb2.TestMessage()
text = '{"int32Value": 0x12345}'
self.assertRaises(json_format.ParseError,
json_format.Parse, text, message)
self.CheckError('{"int32Value": 012345}',
(r'Failed to load JSON: Expecting \'?,\'? delimiter: '
r'line 1'))
self.CheckError('{"int32Value": 1.0}',
'Failed to parse int32Value field: '
'Couldn\'t parse integer: 1.0')
self.CheckError('{"int32Value": " 1 "}',
'Failed to parse int32Value field: '
'Couldn\'t parse integer: " 1 "')
self.CheckError('{"int32Value": 12345678901234567890}',
'Failed to parse int32Value field: Value out of range: '
'12345678901234567890')
self.CheckError('{"int32Value": 1e5}',
'Failed to parse int32Value field: '
'Couldn\'t parse integer: 100000.0')
self.CheckError('{"uint32Value": -1}',
'Failed to parse uint32Value field: Value out of range: -1')
def testInvalidFloatValue(self):
self.CheckError('{"floatValue": "nan"}',
'Failed to parse floatValue field: Couldn\'t '
'parse float "nan", use "NaN" instead')
def testInvalidBytesValue(self):
self.CheckError('{"bytesValue": "AQI"}',
'Failed to parse bytesValue field: Incorrect padding')
self.CheckError('{"bytesValue": "AQI*"}',
'Failed to parse bytesValue field: Incorrect padding')
def testInvalidMap(self):
message = json_format_proto3_pb2.TestMap()
text = '{"int32Map": {"null": 2, "2": 3}}'
self.assertRaisesRegexp(
json_format.ParseError,
'Failed to parse int32Map field: Couldn\'t parse integer: "null"',
json_format.Parse, text, message)
text = '{"int32Map": {1: 2, "2": 3}}'
self.assertRaisesRegexp(
json_format.ParseError,
(r'Failed to load JSON: Expecting property name'
r'( enclosed in double quotes)?: line 1'),
json_format.Parse, text, message)
text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
self.assertRaisesRegexp(
json_format.ParseError,
'Failed to load JSON: duplicate key a',
json_format.Parse, text, message)
text = '{"boolMap": {"null": 1}}'
self.assertRaisesRegexp(
json_format.ParseError,
'Failed to parse boolMap field: Expect "true" or "false", not null.',
json_format.Parse, text, message)
def testInvalidTimestamp(self):
message = json_format_proto3_pb2.TestTimestamp()
text = '{"value": "10000-01-01T00:00:00.00Z"}'
self.assertRaisesRegexp(
json_format.ParseError,
'time data \'10000-01-01T00:00:00\' does not match'
' format \'%Y-%m-%dT%H:%M:%S\'',
json_format.Parse, text, message)
text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
self.assertRaisesRegexp(
json_format.ParseError,
'Failed to parse value field: Failed to parse Timestamp: '
'nanos 0123456789012 more than 9 fractional digits.',
json_format.Parse, text, message)
text = '{"value": "1972-01-01T01:00:00.01+08"}'
self.assertRaisesRegexp(
json_format.ParseError,
(r'Failed to parse value field: Invalid timezone offset value: \+08'),
json_format.Parse, text, message)
# Time smaller than minimum time.
text = '{"value": "0000-01-01T00:00:00Z"}'
self.assertRaisesRegexp(
json_format.ParseError,
'Failed to parse value field: year is out of range',
json_format.Parse, text, message)
# Time bigger than maxinum time.
message.value.seconds = 253402300800
self.assertRaisesRegexp(
json_format.SerializeToJsonError,
'Failed to serialize value field: year is out of range',
json_format.MessageToJson, message)
def testInvalidOneof(self):
message = json_format_proto3_pb2.TestOneof()
text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
self.assertRaisesRegexp(
json_format.ParseError,
'Message type "proto3.TestOneof"'
' should not have multiple "oneof_value" oneof fields.',
json_format.Parse, text, message)
if __name__ == '__main__':
unittest.main()

@ -45,7 +45,6 @@ from google.protobuf import descriptor_database
from google.protobuf import descriptor_pool from google.protobuf import descriptor_pool
from google.protobuf import message_factory from google.protobuf import message_factory
class MessageFactoryTest(unittest.TestCase): class MessageFactoryTest(unittest.TestCase):
def setUp(self): def setUp(self):

@ -43,17 +43,14 @@ abstract interface.
__author__ = 'gps@google.com (Gregory P. Smith)' __author__ = 'gps@google.com (Gregory P. Smith)'
import collections import collections
import copy import copy
import math import math
import operator import operator
import pickle import pickle
import sys
import six import six
import sys
if six.PY3:
long = int
try: try:
import unittest2 as unittest import unittest2 as unittest
@ -68,6 +65,9 @@ from google.protobuf.internal import packed_field_test_pb2
from google.protobuf.internal import test_util from google.protobuf.internal import test_util
from google.protobuf import message from google.protobuf import message
if six.PY3:
long = int
# Python pre-2.6 does not have isinf() or isnan() functions, so we have # Python pre-2.6 does not have isinf() or isnan() functions, so we have
# to provide our own. # to provide our own.
def isnan(val): def isnan(val):
@ -442,7 +442,7 @@ class MessageTest(unittest.TestCase):
message.repeated_nested_message.add().bb = 24 message.repeated_nested_message.add().bb = 24
message.repeated_nested_message.add().bb = 10 message.repeated_nested_message.add().bb = 10
message.repeated_nested_message.sort(key=lambda z: z.bb // 10) message.repeated_nested_message.sort(key=lambda z: z.bb // 10)
self.assertEquals( self.assertEqual(
[13, 11, 10, 21, 20, 24, 33], [13, 11, 10, 21, 20, 24, 33],
[n.bb for n in message.repeated_nested_message]) [n.bb for n in message.repeated_nested_message])
@ -451,7 +451,7 @@ class MessageTest(unittest.TestCase):
pb = message.SerializeToString() pb = message.SerializeToString()
message.Clear() message.Clear()
message.MergeFromString(pb) message.MergeFromString(pb)
self.assertEquals( self.assertEqual(
[13, 11, 10, 21, 20, 24, 33], [13, 11, 10, 21, 20, 24, 33],
[n.bb for n in message.repeated_nested_message]) [n.bb for n in message.repeated_nested_message])
@ -914,7 +914,6 @@ class MessageTest(unittest.TestCase):
with self.assertRaises(pickle.PickleError) as _: with self.assertRaises(pickle.PickleError) as _:
pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL) pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
def testSortEmptyRepeatedCompositeContainer(self, message_module): def testSortEmptyRepeatedCompositeContainer(self, message_module):
"""Exercise a scenario that has led to segfaults in the past. """Exercise a scenario that has led to segfaults in the past.
""" """

@ -50,3 +50,7 @@ message TestMissingEnumValues {
repeated NestedEnum repeated_nested_enum = 2; repeated NestedEnum repeated_nested_enum = 2;
repeated NestedEnum packed_nested_enum = 3 [packed = true]; repeated NestedEnum packed_nested_enum = 3 [packed = true];
} }
message JustString {
required string dummy = 1;
}

@ -34,14 +34,12 @@
try: try:
from collections import OrderedDict from collections import OrderedDict
except ImportError: except ImportError:
from ordereddict import OrderedDict #PY26 from ordereddict import OrderedDict #PY26
try: try:
import unittest2 as unittest #PY26 import unittest2 as unittest
except ImportError: except ImportError:
import unittest import unittest
from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pb2
from google.protobuf import descriptor_pool from google.protobuf import descriptor_pool
from google.protobuf import proto_builder from google.protobuf import proto_builder

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2007 Google Inc. All Rights Reserved.
#
# This code is meant to work on Python 2.4 and above only. # This code is meant to work on Python 2.4 and above only.
# #
# TODO(robinson): Helpers for verbose, common checks like seeing if a # TODO(robinson): Helpers for verbose, common checks like seeing if a

@ -38,14 +38,13 @@ pure-Python protocol compiler.
import copy import copy
import gc import gc
import operator import operator
import six
import struct import struct
try: try:
import unittest2 as unittest import unittest2 as unittest
except ImportError: except ImportError:
import unittest import unittest
import six
from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
@ -1799,7 +1798,6 @@ class ReflectionTest(unittest.TestCase):
# Just check the default value. # Just check the default value.
self.assertEqual(57, msg.inner.value) self.assertEqual(57, msg.inner.value)
# Since we had so many tests for protocol buffer equality, we broke these out # Since we had so many tests for protocol buffer equality, we broke these out
# into separate TestCase classes. # into separate TestCase classes.

@ -37,22 +37,27 @@ try:
except ImportError: except ImportError:
import unittest import unittest
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf import descriptor
from google.protobuf import symbol_database from google.protobuf import symbol_database
class SymbolDatabaseTest(unittest.TestCase): class SymbolDatabaseTest(unittest.TestCase):
def _Database(self): def _Database(self):
db = symbol_database.SymbolDatabase() # TODO(b/17734095): Remove this difference when the C++ implementation
# Register representative types from unittest_pb2. # supports multiple databases.
db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR) if descriptor._USE_C_DESCRIPTORS:
db.RegisterMessage(unittest_pb2.TestAllTypes) return symbol_database.Default()
db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage) else:
db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup) db = symbol_database.SymbolDatabase()
db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup) # Register representative types from unittest_pb2.
db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR) db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR) db.RegisterMessage(unittest_pb2.TestAllTypes)
return db db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
return db
def testGetPrototype(self): def testGetPrototype(self):
instance = self._Database().GetPrototype( instance = self._Database().GetPrototype(

@ -34,6 +34,7 @@
__author__ = 'kenton@google.com (Kenton Varda)' __author__ = 'kenton@google.com (Kenton Varda)'
import re import re
import six import six
import string import string
@ -389,7 +390,7 @@ class TextFormatTest(TextFormatBase):
# Ideally the schemas would be made more similar so these tests could pass. # Ideally the schemas would be made more similar so these tests could pass.
class OnlyWorksWithProto2RightNowTests(TextFormatBase): class OnlyWorksWithProto2RightNowTests(TextFormatBase):
def testPrintAllFieldsPointy(self, message_module): def testPrintAllFieldsPointy(self):
message = unittest_pb2.TestAllTypes() message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message) test_util.SetAllFields(message)
self.CompareToGoldenFile( self.CompareToGoldenFile(

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2008 Google Inc. All Rights Reserved.
"""Provides type checking routines. """Provides type checking routines.
This module defines type checking utilities in the forms of dictionaries: This module defines type checking utilities in the forms of dictionaries:
@ -52,6 +50,7 @@ import six
if six.PY3: if six.PY3:
long = int long = int
from google.protobuf.internal import api_implementation
from google.protobuf.internal import decoder from google.protobuf.internal import decoder
from google.protobuf.internal import encoder from google.protobuf.internal import encoder
from google.protobuf.internal import wire_format from google.protobuf.internal import wire_format

@ -39,7 +39,6 @@ try:
import unittest2 as unittest import unittest2 as unittest
except ImportError: except ImportError:
import unittest import unittest
from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf import unittest_proto3_arena_pb2
@ -262,6 +261,19 @@ class UnknownEnumValuesTest(unittest.TestCase):
decoder(value, 0, len(value), self.message, result_dict) decoder(value, 0, len(value), self.message, result_dict)
return result_dict[field_descriptor] return result_dict[field_descriptor]
def testUnknownParseMismatchEnumValue(self):
just_string = missing_enum_values_pb2.JustString()
just_string.dummy = 'blah'
missing = missing_enum_values_pb2.TestEnumValues()
# The parse is invalid, storing the string proto into the set of
# unknown fields.
missing.ParseFromString(just_string.SerializeToString())
# Fetching the enum field shouldn't crash, instead returning the
# default value.
self.assertEqual(missing.optional_nested_enum, 0)
@SkipIfCppImplementation @SkipIfCppImplementation
def testUnknownEnumValue(self): def testUnknownEnumValue(self):
self.assertFalse(self.missing_message.HasField('optional_nested_enum')) self.assertFalse(self.missing_message.HasField('optional_nested_enum'))

@ -0,0 +1,601 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
# https://developers.google.com/protocol-buffers/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Contains routines for printing protocol messages in JSON format."""
__author__ = 'jieluo@google.com (Jie Luo)'
import base64
from datetime import datetime
import json
import math
import re
from google.protobuf import descriptor
_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
_NUMBER = re.compile(u'[0-9+-][0-9e.+-]*')
_INTEGER = re.compile(u'[0-9+-]')
_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
descriptor.FieldDescriptor.CPPTYPE_UINT32,
descriptor.FieldDescriptor.CPPTYPE_INT64,
descriptor.FieldDescriptor.CPPTYPE_UINT64])
_INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64,
descriptor.FieldDescriptor.CPPTYPE_UINT64])
_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
if str is bytes:
_UNICODETYPE = unicode
else:
_UNICODETYPE = str
class SerializeToJsonError(Exception):
"""Thrown if serialization to JSON fails."""
class ParseError(Exception):
"""Thrown in case of parsing error."""
def MessageToJson(message, including_default_value_fields=False):
"""Converts protobuf message to JSON format.
Args:
message: The protocol buffers message instance to serialize.
including_default_value_fields: If True, singular primitive fields,
repeated fields, and map fields will always be serialized. If
False, only serialize non-empty fields. Singular message fields
and oneof fields are not affected by this option.
Returns:
A string containing the JSON formatted protocol buffer message.
"""
js = _MessageToJsonObject(message, including_default_value_fields)
return json.dumps(js, indent=2)
def _MessageToJsonObject(message, including_default_value_fields):
"""Converts message to an object according to Proto3 JSON Specification."""
message_descriptor = message.DESCRIPTOR
if _IsTimestampMessage(message_descriptor):
return _TimestampMessageToJsonObject(message)
if _IsDurationMessage(message_descriptor):
return _DurationMessageToJsonObject(message)
if _IsFieldMaskMessage(message_descriptor):
return _FieldMaskMessageToJsonObject(message)
if _IsWrapperMessage(message_descriptor):
return _WrapperMessageToJsonObject(message)
return _RegularMessageToJsonObject(message, including_default_value_fields)
def _IsMapEntry(field):
return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
field.message_type.has_options and
field.message_type.GetOptions().map_entry)
def _RegularMessageToJsonObject(message, including_default_value_fields):
"""Converts normal message according to Proto3 JSON Specification."""
js = {}
fields = message.ListFields()
try:
for field, value in fields:
name = field.camelcase_name
if _IsMapEntry(field):
# Convert a map field.
js_map = {}
for key in value:
js_map[key] = _ConvertFieldToJsonObject(
field.message_type.fields_by_name['value'],
value[key], including_default_value_fields)
js[name] = js_map
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
# Convert a repeated field.
repeated = []
for element in value:
repeated.append(_ConvertFieldToJsonObject(
field, element, including_default_value_fields))
js[name] = repeated
else:
js[name] = _ConvertFieldToJsonObject(
field, value, including_default_value_fields)
# Serialize default value if including_default_value_fields is True.
if including_default_value_fields:
message_descriptor = message.DESCRIPTOR
for field in message_descriptor.fields:
# Singular message fields and oneof fields will not be affected.
if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
field.containing_oneof):
continue
name = field.camelcase_name
if name in js:
# Skip the field which has been serailized already.
continue
if _IsMapEntry(field):
js[name] = {}
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
js[name] = []
else:
js[name] = _ConvertFieldToJsonObject(field, field.default_value)
except ValueError as e:
raise SerializeToJsonError(
'Failed to serialize {0} field: {1}'.format(field.name, e))
return js
def _ConvertFieldToJsonObject(
field, value, including_default_value_fields=False):
"""Converts field value according to Proto3 JSON Specification."""
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
return _MessageToJsonObject(value, including_default_value_fields)
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
enum_value = field.enum_type.values_by_number.get(value, None)
if enum_value is not None:
return enum_value.name
else:
raise SerializeToJsonError('Enum field contains an integer value '
'which can not mapped to an enum value.')
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
# Use base64 Data encoding for bytes
return base64.b64encode(value).decode('utf-8')
else:
return value
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
if value:
return True
else:
return False
elif field.cpp_type in _INT64_TYPES:
return str(value)
elif field.cpp_type in _FLOAT_TYPES:
if math.isinf(value):
if value < 0.0:
return '-Infinity'
else:
return 'Infinity'
if math.isnan(value):
return 'NaN'
return value
def _IsTimestampMessage(message_descriptor):
return (message_descriptor.name == 'Timestamp' and
message_descriptor.file.name == 'google/protobuf/timestamp.proto')
def _TimestampMessageToJsonObject(message):
"""Converts Timestamp message according to Proto3 JSON Specification."""
nanos = message.nanos % 1e9
dt = datetime.utcfromtimestamp(
message.seconds + (message.nanos - nanos) / 1e9)
result = dt.isoformat()
if (nanos % 1e9) == 0:
# If there are 0 fractional digits, the fractional
# point '.' should be omitted when serializing.
return result + 'Z'
if (nanos % 1e6) == 0:
# Serialize 3 fractional digits.
return result + '.%03dZ' % (nanos / 1e6)
if (nanos % 1e3) == 0:
# Serialize 6 fractional digits.
return result + '.%06dZ' % (nanos / 1e3)
# Serialize 9 fractional digits.
return result + '.%09dZ' % nanos
def _IsDurationMessage(message_descriptor):
return (message_descriptor.name == 'Duration' and
message_descriptor.file.name == 'google/protobuf/duration.proto')
def _DurationMessageToJsonObject(message):
"""Converts Duration message according to Proto3 JSON Specification."""
if message.seconds < 0 or message.nanos < 0:
result = '-'
seconds = - message.seconds + int((0 - message.nanos) / 1e9)
nanos = (0 - message.nanos) % 1e9
else:
result = ''
seconds = message.seconds + int(message.nanos / 1e9)
nanos = message.nanos % 1e9
result += '%d' % seconds
if (nanos % 1e9) == 0:
# If there are 0 fractional digits, the fractional
# point '.' should be omitted when serializing.
return result + 's'
if (nanos % 1e6) == 0:
# Serialize 3 fractional digits.
return result + '.%03ds' % (nanos / 1e6)
if (nanos % 1e3) == 0:
# Serialize 6 fractional digits.
return result + '.%06ds' % (nanos / 1e3)
# Serialize 9 fractional digits.
return result + '.%09ds' % nanos
def _IsFieldMaskMessage(message_descriptor):
return (message_descriptor.name == 'FieldMask' and
message_descriptor.file.name == 'google/protobuf/field_mask.proto')
def _FieldMaskMessageToJsonObject(message):
"""Converts FieldMask message according to Proto3 JSON Specification."""
result = ''
first = True
for path in message.paths:
if not first:
result += ','
result += path
first = False
return result
def _IsWrapperMessage(message_descriptor):
return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
def _WrapperMessageToJsonObject(message):
return _ConvertFieldToJsonObject(
message.DESCRIPTOR.fields_by_name['value'], message.value)
def _DuplicateChecker(js):
result = {}
for name, value in js:
if name in result:
raise ParseError('Failed to load JSON: duplicate key ' + name)
result[name] = value
return result
def Parse(text, message):
"""Parses a JSON representation of a protocol message into a message.
Args:
text: Message JSON representation.
message: A protocol beffer message to merge into.
Returns:
The same message passed as argument.
Raises::
ParseError: On JSON parsing problems.
"""
if not isinstance(text, _UNICODETYPE): text = text.decode('utf-8')
try:
js = json.loads(text, object_pairs_hook=_DuplicateChecker)
except ValueError as e:
raise ParseError('Failed to load JSON: ' + str(e))
_ConvertFieldValuePair(js, message)
return message
def _ConvertFieldValuePair(js, message):
"""Convert field value pairs into regular message.
Args:
js: A JSON object to convert the field value pairs.
message: A regular protocol message to record the data.
Raises:
ParseError: In case of problems converting.
"""
names = []
message_descriptor = message.DESCRIPTOR
for name in js:
try:
field = message_descriptor.fields_by_camelcase_name.get(name, None)
if not field:
raise ParseError(
'Message type "{0}" has no field named "{1}".'.format(
message_descriptor.full_name, name))
if name in names:
raise ParseError(
'Message type "{0}" should not have multiple "{1}" fields.'.format(
message.DESCRIPTOR.full_name, name))
names.append(name)
# Check no other oneof field is parsed.
if field.containing_oneof is not None:
oneof_name = field.containing_oneof.name
if oneof_name in names:
raise ParseError('Message type "{0}" should not have multiple "{1}" '
'oneof fields.'.format(
message.DESCRIPTOR.full_name, oneof_name))
names.append(oneof_name)
value = js[name]
if value is None:
message.ClearField(field.name)
continue
# Parse field value.
if _IsMapEntry(field):
message.ClearField(field.name)
_ConvertMapFieldValue(value, message, field)
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
message.ClearField(field.name)
if not isinstance(value, list):
raise ParseError('repeated field {0} must be in [] which is '
'{1}'.format(name, value))
for item in value:
if item is None:
continue
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
sub_message = getattr(message, field.name).add()
_ConvertMessage(item, sub_message)
else:
getattr(message, field.name).append(
_ConvertScalarFieldValue(item, field))
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
sub_message = getattr(message, field.name)
_ConvertMessage(value, sub_message)
else:
setattr(message, field.name, _ConvertScalarFieldValue(value, field))
except ParseError as e:
if field and field.containing_oneof is None:
raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
else:
raise ParseError(str(e))
except ValueError as e:
raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
except TypeError as e:
raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
def _ConvertMessage(value, message):
"""Convert a JSON object into a message.
Args:
value: A JSON object.
message: A WKT or regular protocol message to record the data.
Raises:
ParseError: In case of convert problems.
"""
message_descriptor = message.DESCRIPTOR
if _IsTimestampMessage(message_descriptor):
_ConvertTimestampMessage(value, message)
elif _IsDurationMessage(message_descriptor):
_ConvertDurationMessage(value, message)
elif _IsFieldMaskMessage(message_descriptor):
_ConvertFieldMaskMessage(value, message)
elif _IsWrapperMessage(message_descriptor):
_ConvertWrapperMessage(value, message)
else:
_ConvertFieldValuePair(value, message)
def _ConvertTimestampMessage(value, message):
"""Convert a JSON representation into Timestamp message."""
timezone_offset = value.find('Z')
if timezone_offset == -1:
timezone_offset = value.find('+')
if timezone_offset == -1:
timezone_offset = value.rfind('-')
if timezone_offset == -1:
raise ParseError(
'Failed to parse timestamp: missing valid timezone offset.')
time_value = value[0:timezone_offset]
# Parse datetime and nanos
point_position = time_value.find('.')
if point_position == -1:
second_value = time_value
nano_value = ''
else:
second_value = time_value[:point_position]
nano_value = time_value[point_position + 1:]
date_object = datetime.strptime(second_value, _TIMESTAMPFOMAT)
seconds = (date_object - datetime(1970, 1, 1)).total_seconds()
if len(nano_value) > 9:
raise ParseError(
'Failed to parse Timestamp: nanos {0} more than '
'9 fractional digits.'.format(nano_value))
if nano_value:
nanos = round(float('0.' + nano_value) * 1e9)
else:
nanos = 0
# Parse timezone offsets
if value[timezone_offset] == 'Z':
if len(value) != timezone_offset + 1:
raise ParseError(
'Failed to parse timestamp: invalid trailing data {0}.'.format(value))
else:
timezone = value[timezone_offset:]
pos = timezone.find(':')
if pos == -1:
raise ParseError(
'Invalid timezone offset value: ' + timezone)
if timezone[0] == '+':
seconds += (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
else:
seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
# Set seconds and nanos
message.seconds = int(seconds)
message.nanos = int(nanos)
def _ConvertDurationMessage(value, message):
"""Convert a JSON representation into Duration message."""
if value[-1] != 's':
raise ParseError(
'Duration must end with letter "s": ' + value)
try:
duration = float(value[:-1])
except ValueError:
raise ParseError(
'Couldn\'t parse duration: ' + value)
message.seconds = int(duration)
message.nanos = int(round((duration - message.seconds) * 1e9))
def _ConvertFieldMaskMessage(value, message):
"""Convert a JSON representation into FieldMask message."""
for path in value.split(','):
message.paths.append(path)
def _ConvertWrapperMessage(value, message):
"""Convert a JSON representation into Wrapper message."""
field = message.DESCRIPTOR.fields_by_name['value']
setattr(message, 'value', _ConvertScalarFieldValue(value, field))
def _ConvertMapFieldValue(value, message, field):
"""Convert map field value for a message map field.
Args:
value: A JSON object to convert the map field value.
message: A protocol message to record the converted data.
field: The descriptor of the map field to be converted.
Raises:
ParseError: In case of convert problems.
"""
if not isinstance(value, dict):
raise ParseError(
'Map fieled {0} must be in {} which is {1}.'.format(field.name, value))
key_field = field.message_type.fields_by_name['key']
value_field = field.message_type.fields_by_name['value']
for key in value:
key_value = _ConvertScalarFieldValue(key, key_field, True)
if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
_ConvertMessage(value[key], getattr(message, field.name)[key_value])
else:
getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
value[key], value_field)
def _ConvertScalarFieldValue(value, field, require_quote=False):
"""Convert a single scalar field value.
Args:
value: A scalar value to convert the scalar field value.
field: The descriptor of the field to convert.
require_quote: If True, '"' is required for the field value.
Returns:
The converted scalar field value
Raises:
ParseError: In case of convert problems.
"""
if field.cpp_type in _INT_TYPES:
return _ConvertInteger(value)
elif field.cpp_type in _FLOAT_TYPES:
return _ConvertFloat(value)
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
return _ConvertBool(value, require_quote)
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
return base64.b64decode(value)
else:
return value
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
# Convert an enum value.
enum_value = field.enum_type.values_by_name.get(value, None)
if enum_value is None:
raise ParseError(
'Enum value must be a string literal with double quotes. '
'Type "{0}" has no value named {1}.'.format(
field.enum_type.full_name, value))
return enum_value.number
def _ConvertInteger(value):
"""Convert an integer.
Args:
value: A scalar value to convert.
Returns:
The integer value.
Raises:
ParseError: If an integer couldn't be consumed.
"""
if isinstance(value, float):
raise ParseError('Couldn\'t parse integer: {0}'.format(value))
if isinstance(value, _UNICODETYPE) and not _INTEGER.match(value):
raise ParseError('Couldn\'t parse integer: "{0}"'.format(value))
return int(value)
def _ConvertFloat(value):
"""Convert an floating point number."""
if value == 'nan':
raise ParseError('Couldn\'t parse float "nan", use "NaN" instead')
try:
# Assume Python compatible syntax.
return float(value)
except ValueError:
# Check alternative spellings.
if value == '-Infinity':
return float('-inf')
elif value == 'Infinity':
return float('inf')
elif value == 'NaN':
return float('nan')
else:
raise ParseError('Couldn\'t parse float: {0}'.format(value))
def _ConvertBool(value, require_quote):
"""Convert a boolean value.
Args:
value: A scalar value to convert.
require_quote: If True, '"' is required for the boolean value.
Returns:
The bool parsed.
Raises:
ParseError: If a boolean value couldn't be consumed.
"""
if require_quote:
if value == 'true':
return True
elif value == 'false':
return False
else:
raise ParseError('Expect "true" or "false", not {0}.'.format(value))
if not isinstance(value, bool):
raise ParseError('Expected true or false without quotes.')
return value

@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2012 Google Inc. All Rights Reserved.
"""Provides a factory class for generating dynamic messages. """Provides a factory class for generating dynamic messages.
The easiest way to use this class is if you have access to the FileDescriptor The easiest way to use this class is if you have access to the FileDescriptor

@ -48,7 +48,7 @@ def _GetMessageFromFactory(factory, full_name):
factory: a MessageFactory instance. factory: a MessageFactory instance.
full_name: str, the fully qualified name of the proto type. full_name: str, the fully qualified name of the proto type.
Returns: Returns:
a class, for the type identified by full_name. A class, for the type identified by full_name.
Raises: Raises:
KeyError, if the proto is not found in the factory's descriptor pool. KeyError, if the proto is not found in the factory's descriptor pool.
""" """
@ -57,7 +57,7 @@ def _GetMessageFromFactory(factory, full_name):
return proto_cls return proto_cls
def MakeSimpleProtoClass(fields, full_name, pool=None): def MakeSimpleProtoClass(fields, full_name=None, pool=None):
"""Create a Protobuf class whose fields are basic types. """Create a Protobuf class whose fields are basic types.
Note: this doesn't validate field names! Note: this doesn't validate field names!
@ -66,18 +66,20 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
fields: dict of {name: field_type} mappings for each field in the proto. If fields: dict of {name: field_type} mappings for each field in the proto. If
this is an OrderedDict the order will be maintained, otherwise the this is an OrderedDict the order will be maintained, otherwise the
fields will be sorted by name. fields will be sorted by name.
full_name: str, the fully-qualified name of the proto type. full_name: optional str, the fully-qualified name of the proto type.
pool: optional DescriptorPool instance. pool: optional DescriptorPool instance.
Returns: Returns:
a class, the new protobuf class with a FileDescriptor. a class, the new protobuf class with a FileDescriptor.
""" """
factory = message_factory.MessageFactory(pool=pool) factory = message_factory.MessageFactory(pool=pool)
try:
proto_cls = _GetMessageFromFactory(factory, full_name) if full_name is not None:
return proto_cls try:
except KeyError: proto_cls = _GetMessageFromFactory(factory, full_name)
# The factory's DescriptorPool doesn't know about this class yet. return proto_cls
pass except KeyError:
# The factory's DescriptorPool doesn't know about this class yet.
pass
# Get a list of (name, field_type) tuples from the fields dict. If fields was # Get a list of (name, field_type) tuples from the fields dict. If fields was
# an OrderedDict we keep the order, but otherwise we sort the field to ensure # an OrderedDict we keep the order, but otherwise we sort the field to ensure
@ -94,6 +96,25 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
fields_hash.update(str(f_type).encode('utf-8')) fields_hash.update(str(f_type).encode('utf-8'))
proto_file_name = fields_hash.hexdigest() + '.proto' proto_file_name = fields_hash.hexdigest() + '.proto'
# If the proto is anonymous, use the same hash to name it.
if full_name is None:
full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' +
fields_hash.hexdigest())
try:
proto_cls = _GetMessageFromFactory(factory, full_name)
return proto_cls
except KeyError:
# The factory's DescriptorPool doesn't know about this class yet.
pass
# This is the first time we see this proto: add a new descriptor to the pool.
factory.pool.Add(
_MakeFileDescriptorProto(proto_file_name, full_name, field_items))
return _GetMessageFromFactory(factory, full_name)
def _MakeFileDescriptorProto(proto_file_name, full_name, field_items):
"""Populate FileDescriptorProto for MessageFactory's DescriptorPool."""
package, name = full_name.rsplit('.', 1) package, name = full_name.rsplit('.', 1)
file_proto = descriptor_pb2.FileDescriptorProto() file_proto = descriptor_pb2.FileDescriptorProto()
file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name) file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name)
@ -106,6 +127,4 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
field_proto.number = f_number field_proto.number = f_number
field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
field_proto.type = f_type field_proto.type = f_type
return file_proto
factory.pool.Add(file_proto)
return _GetMessageFromFactory(factory, full_name)

@ -223,8 +223,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
options.SerializeToString(&serialized); options.SerializeToString(&serialized);
io::CodedInputStream input( io::CodedInputStream input(
reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size()); reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
input.SetExtensionRegistry(pool->pool, input.SetExtensionRegistry(pool->pool, pool->message_factory);
GetDescriptorPool()->message_factory);
bool success = cmsg->message->MergePartialFromCodedStream(&input); bool success = cmsg->message->MergePartialFromCodedStream(&input);
if (!success) { if (!success) {
PyErr_Format(PyExc_ValueError, "Error parsing Options message"); PyErr_Format(PyExc_ValueError, "Error parsing Options message");
@ -414,8 +413,14 @@ static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
} }
static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
// Retuns the canonical class for the given descriptor.
// This is the class that was registered with the primary descriptor pool
// which contains this descriptor.
// This might not be the one you expect! For example the returned object does
// not know about extensions defined in a custom pool.
PyObject* concrete_class(cdescriptor_pool::GetMessageClass( PyObject* concrete_class(cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), _GetDescriptor(self))); GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()),
_GetDescriptor(self)));
Py_XINCREF(concrete_class); Py_XINCREF(concrete_class);
return concrete_class; return concrete_class;
} }
@ -424,6 +429,11 @@ static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
return NewMessageFieldsByName(_GetDescriptor(self)); return NewMessageFieldsByName(_GetDescriptor(self));
} }
static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self,
void *closure) {
return NewMessageFieldsByCamelcaseName(_GetDescriptor(self));
}
static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) { static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
return NewMessageFieldsByNumber(_GetDescriptor(self)); return NewMessageFieldsByNumber(_GetDescriptor(self));
} }
@ -564,6 +574,8 @@ static PyGetSetDef Getters[] = {
{ "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"}, { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"},
{ "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"}, { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"},
{ "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL,
"Fields by camelCase name"},
{ "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"}, { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"},
{ "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"}, { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"},
{ "nested_types_by_name", (getter)GetNestedTypesByName, NULL, { "nested_types_by_name", (getter)GetNestedTypesByName, NULL,
@ -662,6 +674,10 @@ static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
return PyString_FromCppString(_GetDescriptor(self)->name()); return PyString_FromCppString(_GetDescriptor(self)->name());
} }
static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) {
return PyString_FromCppString(_GetDescriptor(self)->camelcase_name());
}
static PyObject* GetType(PyBaseDescriptor *self, void *closure) { static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
return PyInt_FromLong(_GetDescriptor(self)->type()); return PyInt_FromLong(_GetDescriptor(self)->type());
} }
@ -850,6 +866,7 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
static PyGetSetDef Getters[] = { static PyGetSetDef Getters[] = {
{ "full_name", (getter)GetFullName, NULL, "Full name"}, { "full_name", (getter)GetFullName, NULL, "Full name"},
{ "name", (getter)GetName, NULL, "Unqualified name"}, { "name", (getter)GetName, NULL, "Unqualified name"},
{ "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
{ "type", (getter)GetType, NULL, "C++ Type"}, { "type", (getter)GetType, NULL, "C++ Type"},
{ "cpp_type", (getter)GetCppType, NULL, "C++ Type"}, { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
{ "label", (getter)GetLabel, NULL, "Label"}, { "label", (getter)GetLabel, NULL, "Label"},
@ -1070,6 +1087,15 @@ PyObject* PyEnumDescriptor_FromDescriptor(
&PyEnumDescriptor_Type, enum_descriptor, NULL); &PyEnumDescriptor_Type, enum_descriptor, NULL);
} }
const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
return NULL;
}
return reinterpret_cast<const EnumDescriptor*>(
reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
}
namespace enumvalue_descriptor { namespace enumvalue_descriptor {
// Unchecked accessor to the C++ pointer. // Unchecked accessor to the C++ pointer.
@ -1359,6 +1385,15 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
return py_descriptor; return py_descriptor;
} }
const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
return NULL;
}
return reinterpret_cast<const FileDescriptor*>(
reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
}
namespace oneof_descriptor { namespace oneof_descriptor {
// Unchecked accessor to the C++ pointer. // Unchecked accessor to the C++ pointer.

@ -72,6 +72,8 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
// exception set. // exception set.
const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj); const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj);
const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj); const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj);
const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj);
const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj);
// Returns the raw C++ pointer. // Returns the raw C++ pointer.
const void* PyDescriptor_AsVoidPtr(PyObject* obj); const void* PyDescriptor_AsVoidPtr(PyObject* obj);

@ -79,9 +79,12 @@ struct PyContainer;
typedef int (*CountMethod)(PyContainer* self); typedef int (*CountMethod)(PyContainer* self);
typedef const void* (*GetByIndexMethod)(PyContainer* self, int index); typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name); typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
const string& name);
typedef const void* (*GetByNumberMethod)(PyContainer* self, int index); typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor); typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
typedef const string& (*GetItemNameMethod)(const void* descriptor); typedef const string& (*GetItemNameMethod)(const void* descriptor);
typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor);
typedef int (*GetItemNumberMethod)(const void* descriptor); typedef int (*GetItemNumberMethod)(const void* descriptor);
typedef int (*GetItemIndexMethod)(const void* descriptor); typedef int (*GetItemIndexMethod)(const void* descriptor);
@ -95,6 +98,9 @@ struct DescriptorContainerDef {
// Retrieve item by name (usually a call to some 'FindByName' method). // Retrieve item by name (usually a call to some 'FindByName' method).
// Used by "by_name" mappings. // Used by "by_name" mappings.
GetByNameMethod get_by_name_fn; GetByNameMethod get_by_name_fn;
// Retrieve item by camelcase name (usually a call to some
// 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
GetByCamelcaseNameMethod get_by_camelcase_name_fn;
// Retrieve item by declared number (field tag, or enum value). // Retrieve item by declared number (field tag, or enum value).
// Used by "by_number" mappings. // Used by "by_number" mappings.
GetByNumberMethod get_by_number_fn; GetByNumberMethod get_by_number_fn;
@ -102,6 +108,9 @@ struct DescriptorContainerDef {
NewObjectFromItemMethod new_object_from_item_fn; NewObjectFromItemMethod new_object_from_item_fn;
// Retrieve the name of an item. Used by iterators on "by_name" mappings. // Retrieve the name of an item. Used by iterators on "by_name" mappings.
GetItemNameMethod get_item_name_fn; GetItemNameMethod get_item_name_fn;
// Retrieve the camelcase name of an item. Used by iterators on
// "by_camelcase_name" mappings.
GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
// Retrieve the number of an item. Used by iterators on "by_number" mappings. // Retrieve the number of an item. Used by iterators on "by_number" mappings.
GetItemNumberMethod get_item_number_fn; GetItemNumberMethod get_item_number_fn;
// Retrieve the index of an item for the container type. // Retrieve the index of an item for the container type.
@ -125,6 +134,7 @@ struct PyContainer {
enum ContainerKind { enum ContainerKind {
KIND_SEQUENCE, KIND_SEQUENCE,
KIND_BYNAME, KIND_BYNAME,
KIND_BYCAMELCASENAME,
KIND_BYNUMBER, KIND_BYNUMBER,
} kind; } kind;
}; };
@ -172,6 +182,23 @@ static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
self, string(name, name_size)); self, string(name, name_size));
return true; return true;
} }
case PyContainer::KIND_BYCAMELCASENAME:
{
char* camelcase_name;
Py_ssize_t name_size;
if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
// Not a string, cannot be in the container.
PyErr_Clear();
*item = NULL;
return true;
}
return false;
}
*item = self->container_def->get_by_camelcase_name_fn(
self, string(camelcase_name, name_size));
return true;
}
case PyContainer::KIND_BYNUMBER: case PyContainer::KIND_BYNUMBER:
{ {
Py_ssize_t number = PyNumber_AsSsize_t(key, NULL); Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
@ -203,6 +230,12 @@ static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
const string& name(self->container_def->get_item_name_fn(item)); const string& name(self->container_def->get_item_name_fn(item));
return PyString_FromStringAndSize(name.c_str(), name.size()); return PyString_FromStringAndSize(name.c_str(), name.size());
} }
case PyContainer::KIND_BYCAMELCASENAME:
{
const string& name(
self->container_def->get_item_camelcase_name_fn(item));
return PyString_FromStringAndSize(name.c_str(), name.size());
}
case PyContainer::KIND_BYNUMBER: case PyContainer::KIND_BYNUMBER:
{ {
int value = self->container_def->get_item_number_fn(item); int value = self->container_def->get_item_number_fn(item);
@ -276,6 +309,9 @@ static PyObject* ContainerRepr(PyContainer* self) {
case PyContainer::KIND_BYNAME: case PyContainer::KIND_BYNAME:
kind = "mapping by name"; kind = "mapping by name";
break; break;
case PyContainer::KIND_BYCAMELCASENAME:
kind = "mapping by camelCase name";
break;
case PyContainer::KIND_BYNUMBER: case PyContainer::KIND_BYNUMBER:
kind = "mapping by number"; kind = "mapping by number";
break; break;
@ -731,6 +767,18 @@ static PyObject* NewMappingByName(
return reinterpret_cast<PyObject*>(self); return reinterpret_cast<PyObject*>(self);
} }
static PyObject* NewMappingByCamelcaseName(
DescriptorContainerDef* container_def, const void* descriptor) {
PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
if (self == NULL) {
return NULL;
}
self->descriptor = descriptor;
self->container_def = container_def;
self->kind = PyContainer::KIND_BYCAMELCASENAME;
return reinterpret_cast<PyObject*>(self);
}
static PyObject* NewMappingByNumber( static PyObject* NewMappingByNumber(
DescriptorContainerDef* container_def, const void* descriptor) { DescriptorContainerDef* container_def, const void* descriptor) {
if (container_def->get_by_number_fn == NULL || if (container_def->get_by_number_fn == NULL ||
@ -889,6 +937,11 @@ static ItemDescriptor GetByName(PyContainer* self, const string& name) {
return GetDescriptor(self)->FindFieldByName(name); return GetDescriptor(self)->FindFieldByName(name);
} }
static ItemDescriptor GetByCamelcaseName(PyContainer* self,
const string& name) {
return GetDescriptor(self)->FindFieldByCamelcaseName(name);
}
static ItemDescriptor GetByNumber(PyContainer* self, int number) { static ItemDescriptor GetByNumber(PyContainer* self, int number) {
return GetDescriptor(self)->FindFieldByNumber(number); return GetDescriptor(self)->FindFieldByNumber(number);
} }
@ -905,6 +958,10 @@ static const string& GetItemName(ItemDescriptor item) {
return item->name(); return item->name();
} }
static const string& GetItemCamelcaseName(ItemDescriptor item) {
return item->camelcase_name();
}
static int GetItemNumber(ItemDescriptor item) { static int GetItemNumber(ItemDescriptor item) {
return item->number(); return item->number();
} }
@ -918,9 +975,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)GetByCamelcaseName,
(GetByNumberMethod)GetByNumber, (GetByNumberMethod)GetByNumber,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)GetItemCamelcaseName,
(GetItemNumberMethod)GetItemNumber, (GetItemNumberMethod)GetItemNumber,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -931,6 +990,11 @@ PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
return descriptor::NewMappingByName(&fields::ContainerDef, descriptor); return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
} }
PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
descriptor);
}
PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) { PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor); return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
} }
@ -972,9 +1036,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1022,9 +1088,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1094,9 +1162,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL, (GetItemIndexMethod)NULL,
}; };
@ -1140,9 +1210,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1190,9 +1262,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1258,9 +1332,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)GetByNumber, (GetByNumberMethod)GetByNumber,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)GetItemNumber, (GetItemNumberMethod)GetItemNumber,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1314,9 +1390,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL, (GetByNameMethod)NULL,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL, (GetItemNameMethod)NULL,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1370,9 +1448,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1416,9 +1496,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1462,9 +1544,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName, (GetByNameMethod)GetByName,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName, (GetItemNameMethod)GetItemName,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex, (GetItemIndexMethod)GetItemIndex,
}; };
@ -1496,9 +1580,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL, (GetByNameMethod)NULL,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL, (GetItemNameMethod)NULL,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL, (GetItemIndexMethod)NULL,
}; };
@ -1530,9 +1616,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count, (CountMethod)Count,
(GetByIndexMethod)GetByIndex, (GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL, (GetByNameMethod)NULL,
(GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL, (GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem, (NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL, (GetItemNameMethod)NULL,
(GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL, (GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL, (GetItemIndexMethod)NULL,
}; };

@ -54,6 +54,7 @@ bool InitDescriptorMappingTypes();
namespace message_descriptor { namespace message_descriptor {
PyObject* NewMessageFieldsByName(const Descriptor* descriptor); PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor); PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
PyObject* NewMessageFieldsSeq(const Descriptor* descriptor); PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);

@ -108,6 +108,7 @@ static void Dealloc(PyDescriptorPool* self) {
Py_DECREF(it->second); Py_DECREF(it->second);
} }
delete self->descriptor_options; delete self->descriptor_options;
delete self->pool;
delete self->message_factory; delete self->message_factory;
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
} }
@ -131,22 +132,9 @@ PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) {
} }
// Add a message class to our database. // Add a message class to our database.
const Descriptor* RegisterMessageClass( int RegisterMessageClass(PyDescriptorPool* self,
PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) { const Descriptor *message_descriptor,
ScopedPyObjectPtr full_message_name( PyObject *message_class) {
PyObject_GetAttrString(descriptor, "full_name"));
Py_ssize_t name_size;
char* name;
if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) {
return NULL;
}
const Descriptor *message_descriptor =
self->pool->FindMessageTypeByName(string(name, name_size));
if (!message_descriptor) {
PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'",
name);
return NULL;
}
Py_INCREF(message_class); Py_INCREF(message_class);
typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
std::pair<iterator, bool> ret = self->classes_by_descriptor->insert( std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
@ -156,7 +144,7 @@ const Descriptor* RegisterMessageClass(
Py_DECREF(ret.first->second); Py_DECREF(ret.first->second);
ret.first->second = message_class; ret.first->second = message_class;
} }
return message_descriptor; return 0;
} }
// Retrieve the message class added to our database. // Retrieve the message class added to our database.
@ -260,6 +248,80 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
return PyOneofDescriptor_FromDescriptor(oneof_descriptor); return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
} }
PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
Py_ssize_t name_size;
char* name;
if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
return NULL;
}
const FileDescriptor* file_descriptor =
self->pool->FindFileContainingSymbol(string(name, name_size));
if (file_descriptor == NULL) {
PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
return NULL;
}
return PyFileDescriptor_FromDescriptor(file_descriptor);
}
// These functions should not exist -- the only valid way to create
// descriptors is to call Add() or AddSerializedFile().
// But these AddDescriptor() functions were created in Python and some people
// call them, so we support them for now for compatibility.
// However we do check that the existing descriptor already exists in the pool,
// which appears to always be true for existing calls -- but then why do people
// call a function that will just be a no-op?
// TODO(amauryfa): Need to investigate further.
PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
const FileDescriptor* file_descriptor =
PyFileDescriptor_AsDescriptor(descriptor);
if (!file_descriptor) {
return NULL;
}
if (file_descriptor !=
self->pool->FindFileByName(file_descriptor->name())) {
PyErr_Format(PyExc_ValueError,
"The file descriptor %s does not belong to this pool",
file_descriptor->name().c_str());
return NULL;
}
Py_RETURN_NONE;
}
PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
const Descriptor* message_descriptor =
PyMessageDescriptor_AsDescriptor(descriptor);
if (!message_descriptor) {
return NULL;
}
if (message_descriptor !=
self->pool->FindMessageTypeByName(message_descriptor->full_name())) {
PyErr_Format(PyExc_ValueError,
"The message descriptor %s does not belong to this pool",
message_descriptor->full_name().c_str());
return NULL;
}
Py_RETURN_NONE;
}
PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
const EnumDescriptor* enum_descriptor =
PyEnumDescriptor_AsDescriptor(descriptor);
if (!enum_descriptor) {
return NULL;
}
if (enum_descriptor !=
self->pool->FindEnumTypeByName(enum_descriptor->full_name())) {
PyErr_Format(PyExc_ValueError,
"The enum descriptor %s does not belong to this pool",
enum_descriptor->full_name().c_str());
return NULL;
}
Py_RETURN_NONE;
}
// The code below loads new Descriptors from a serialized FileDescriptorProto. // The code below loads new Descriptors from a serialized FileDescriptorProto.
@ -341,6 +403,15 @@ static PyMethodDef Methods[] = {
{ "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O, { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O,
"Adds a serialized FileDescriptorProto to this pool." }, "Adds a serialized FileDescriptorProto to this pool." },
// TODO(amauryfa): Understand why the Python implementation differs from
// this one, ask users to use another API and deprecate these functions.
{ "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O,
"No-op. Add() must have been called before." },
{ "AddDescriptor", (PyCFunction)AddDescriptor, METH_O,
"No-op. Add() must have been called before." },
{ "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O,
"No-op. Add() must have been called before." },
{ "FindFileByName", (PyCFunction)FindFileByName, METH_O, { "FindFileByName", (PyCFunction)FindFileByName, METH_O,
"Searches for a file descriptor by its .proto name." }, "Searches for a file descriptor by its .proto name." },
{ "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O, { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O,
@ -353,6 +424,9 @@ static PyMethodDef Methods[] = {
"Searches for enum type descriptor by full name." }, "Searches for enum type descriptor by full name." },
{ "FindOneofByName", (PyCFunction)FindOneofByName, METH_O, { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
"Searches for oneof descriptor by full name." }, "Searches for oneof descriptor by full name." },
{ "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
"Gets the FileDescriptor containing the specified symbol." },
{NULL} {NULL}
}; };
@ -420,7 +494,7 @@ bool InitDescriptorPool() {
return true; return true;
} }
PyDescriptorPool* GetDescriptorPool() { PyDescriptorPool* GetDefaultDescriptorPool() {
return python_generated_pool; return python_generated_pool;
} }
@ -432,7 +506,7 @@ PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
} }
hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it = hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it =
descriptor_pool_map.find(pool); descriptor_pool_map.find(pool);
if (it != descriptor_pool_map.end()) { if (it == descriptor_pool_map.end()) {
PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool"); PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
return NULL; return NULL;
} }

@ -89,12 +89,10 @@ const Descriptor* FindMessageTypeByName(PyDescriptorPool* self,
const string& name); const string& name);
// Registers a new Python class for the given message descriptor. // Registers a new Python class for the given message descriptor.
// Returns the message Descriptor. // On error, returns -1 with a Python exception set.
// On error, returns NULL with a Python exception set. int RegisterMessageClass(PyDescriptorPool* self,
const Descriptor* RegisterMessageClass( const Descriptor* message_descriptor,
PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor); PyObject* message_class);
// The function below are also exposed as methods of the DescriptorPool type.
// Retrieves the Python class registered with the given message descriptor. // Retrieves the Python class registered with the given message descriptor.
// //
@ -103,6 +101,8 @@ const Descriptor* RegisterMessageClass(
PyObject* GetMessageClass(PyDescriptorPool* self, PyObject* GetMessageClass(PyDescriptorPool* self,
const Descriptor* message_descriptor); const Descriptor* message_descriptor);
// The functions below are also exposed as methods of the DescriptorPool type.
// Looks up a message by name. Returns a PyMessageDescriptor corresponding to // Looks up a message by name. Returns a PyMessageDescriptor corresponding to
// the field on success, or NULL on failure. // the field on success, or NULL on failure.
// //
@ -136,8 +136,9 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg);
} // namespace cdescriptor_pool } // namespace cdescriptor_pool
// Retrieve the global descriptor pool owned by the _message module. // Retrieve the global descriptor pool owned by the _message module.
// This is the one used by pb2.py generated modules.
// Returns a *borrowed* reference. // Returns a *borrowed* reference.
PyDescriptorPool* GetDescriptorPool(); PyDescriptorPool* GetDefaultDescriptorPool();
// Retrieve the python descriptor pool owning a C++ descriptor pool. // Retrieve the python descriptor pool owning a C++ descriptor pool.
// Returns a *borrowed* reference. // Returns a *borrowed* reference.

@ -123,7 +123,8 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) {
if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject *message_class = cdescriptor_pool::GetMessageClass( PyObject *message_class = cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), descriptor->message_type()); cmessage::GetDescriptorPoolForMessage(self->parent),
descriptor->message_type());
if (message_class == NULL) { if (message_class == NULL) {
return NULL; return NULL;
} }

@ -55,6 +55,7 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h> #include <google/protobuf/message.h>
#include <google/protobuf/text_format.h> #include <google/protobuf/text_format.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/pyext/descriptor.h> #include <google/protobuf/pyext/descriptor.h>
#include <google/protobuf/pyext/descriptor_pool.h> #include <google/protobuf/pyext/descriptor_pool.h>
#include <google/protobuf/pyext/extension_dict.h> #include <google/protobuf/pyext/extension_dict.h>
@ -107,8 +108,18 @@ struct PyMessageMeta {
// C++ descriptor of this message. // C++ descriptor of this message.
const Descriptor* message_descriptor; const Descriptor* message_descriptor;
// Owned reference, used to keep the pointer above alive. // Owned reference, used to keep the pointer above alive.
PyObject* py_message_descriptor; PyObject* py_message_descriptor;
// The Python DescriptorPool used to create the class. It is needed to resolve
// fields descriptors, including extensions fields; its C++ MessageFactory is
// used to instantiate submessages.
// This can be different from DESCRIPTOR.file.pool, in the case of a custom
// DescriptorPool which defines new extensions.
// We own the reference, because it's important to keep the descriptors and
// factory alive.
PyDescriptorPool* py_descriptor_pool;
}; };
namespace message_meta { namespace message_meta {
@ -139,18 +150,10 @@ static bool AddFieldNumberToClass(
// Finalize the creation of the Message class. // Finalize the creation of the Message class.
// Called from its metaclass: GeneratedProtocolMessageType.__init__(). static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
const Descriptor* message_descriptor =
cdescriptor_pool::RegisterMessageClass(
GetDescriptorPool(), cls, descriptor);
if (message_descriptor == NULL) {
return -1;
}
// If there are extension_ranges, the message is "extendable", and extension // If there are extension_ranges, the message is "extendable", and extension
// classes will register themselves in this class. // classes will register themselves in this class.
if (message_descriptor->extension_range_count() > 0) { if (descriptor->extension_range_count() > 0) {
ScopedPyObjectPtr by_name(PyDict_New()); ScopedPyObjectPtr by_name(PyDict_New());
if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) { if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) {
return -1; return -1;
@ -162,8 +165,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
} }
// For each field set: cls.<field>_FIELD_NUMBER = <number> // For each field set: cls.<field>_FIELD_NUMBER = <number>
for (int i = 0; i < message_descriptor->field_count(); ++i) { for (int i = 0; i < descriptor->field_count(); ++i) {
if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) { if (!AddFieldNumberToClass(cls, descriptor->field(i))) {
return -1; return -1;
} }
} }
@ -173,8 +176,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
// The enum descriptor we get from // The enum descriptor we get from
// <messagedescriptor>.enum_types_by_name[name] // <messagedescriptor>.enum_types_by_name[name]
// which was built previously. // which was built previously.
for (int i = 0; i < message_descriptor->enum_type_count(); ++i) { for (int i = 0; i < descriptor->enum_type_count(); ++i) {
const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i); const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
ScopedPyObjectPtr enum_type( ScopedPyObjectPtr enum_type(
PyEnumDescriptor_FromDescriptor(enum_descriptor)); PyEnumDescriptor_FromDescriptor(enum_descriptor));
if (enum_type == NULL) { if (enum_type == NULL) {
@ -212,8 +215,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
// Extension descriptors come from // Extension descriptors come from
// <message descriptor>.extensions_by_name[name] // <message descriptor>.extensions_by_name[name]
// which was defined previously. // which was defined previously.
for (int i = 0; i < message_descriptor->extension_count(); ++i) { for (int i = 0; i < descriptor->extension_count(); ++i) {
const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i); const google::protobuf::FieldDescriptor* field = descriptor->extension(i);
ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field));
if (extension_field == NULL) { if (extension_field == NULL) {
return -1; return -1;
@ -258,14 +261,14 @@ static PyObject* New(PyTypeObject* type,
} }
// Check dict['DESCRIPTOR'] // Check dict['DESCRIPTOR']
PyObject* descriptor = PyDict_GetItem(dict, kDESCRIPTOR); PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
if (descriptor == NULL) { if (py_descriptor == NULL) {
PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
return NULL; return NULL;
} }
if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) { if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s", PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
descriptor->ob_type->tp_name); py_descriptor->ob_type->tp_name);
return NULL; return NULL;
} }
@ -291,14 +294,28 @@ static PyObject* New(PyTypeObject* type,
} }
// Cache the descriptor, both as Python object and as C++ pointer. // Cache the descriptor, both as Python object and as C++ pointer.
const Descriptor* message_descriptor = const Descriptor* descriptor =
PyMessageDescriptor_AsDescriptor(descriptor); PyMessageDescriptor_AsDescriptor(py_descriptor);
if (message_descriptor == NULL) { if (descriptor == NULL) {
return NULL;
}
Py_INCREF(py_descriptor);
newtype->py_message_descriptor = py_descriptor;
newtype->message_descriptor = descriptor;
// TODO(amauryfa): Don't always use the canonical pool of the descriptor,
// use the MessageFactory optionally passed in the class dict.
newtype->py_descriptor_pool = GetDescriptorPool_FromPool(
descriptor->file()->pool());
if (newtype->py_descriptor_pool == NULL) {
return NULL;
}
Py_INCREF(newtype->py_descriptor_pool);
// Add the message to the DescriptorPool.
if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool,
descriptor, result) < 0) {
return NULL; return NULL;
} }
Py_INCREF(descriptor);
newtype->py_message_descriptor = descriptor;
newtype->message_descriptor = message_descriptor;
// Continue with type initialization: add other descriptors, enum values... // Continue with type initialization: add other descriptors, enum values...
if (AddDescriptors(result, descriptor) < 0) { if (AddDescriptors(result, descriptor) < 0) {
@ -309,6 +326,7 @@ static PyObject* New(PyTypeObject* type,
static void Dealloc(PyMessageMeta *self) { static void Dealloc(PyMessageMeta *self) {
Py_DECREF(self->py_message_descriptor); Py_DECREF(self->py_message_descriptor);
Py_DECREF(self->py_descriptor_pool);
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
} }
@ -381,12 +399,20 @@ PyTypeObject PyMessageMeta_Type = {
message_meta::New, // tp_new message_meta::New, // tp_new
}; };
static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { static PyMessageMeta* CheckMessageClass(PyTypeObject* cls) {
if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) { if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) {
PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name); PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
return NULL; return NULL;
} }
return reinterpret_cast<PyMessageMeta*>(cls)->message_descriptor; return reinterpret_cast<PyMessageMeta*>(cls);
}
static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
PyMessageMeta* type = CheckMessageClass(cls);
if (type == NULL) {
return NULL;
}
return type->message_descriptor;
} }
// Forward declarations // Forward declarations
@ -723,6 +749,17 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
namespace cmessage { namespace cmessage {
PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) {
// No need to check the type: the type of instances of CMessage is always
// an instance of PyMessageMeta. Let's prove it with a debug-only check.
GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type));
return reinterpret_cast<PyMessageMeta*>(Py_TYPE(message))->py_descriptor_pool;
}
MessageFactory* GetFactoryForMessage(CMessage* message) {
return GetDescriptorPoolForMessage(message)->message_factory;
}
static int MaybeReleaseOverlappingOneofField( static int MaybeReleaseOverlappingOneofField(
CMessage* cmessage, CMessage* cmessage,
const FieldDescriptor* field) { const FieldDescriptor* field) {
@ -773,7 +810,7 @@ static Message* GetMutableMessage(
return NULL; return NULL;
} }
return reflection->MutableMessage( return reflection->MutableMessage(
parent_message, parent_field, GetDescriptorPool()->message_factory); parent_message, parent_field, GetFactoryForMessage(parent));
} }
struct FixupMessageReference : public ChildVisitor { struct FixupMessageReference : public ChildVisitor {
@ -814,10 +851,7 @@ int AssureWritable(CMessage* self) {
// If parent is NULL but we are trying to modify a read-only message, this // If parent is NULL but we are trying to modify a read-only message, this
// is a reference to a constant default instance that needs to be replaced // is a reference to a constant default instance that needs to be replaced
// with a mutable top-level message. // with a mutable top-level message.
const Message* prototype = self->message = self->message->New();
GetDescriptorPool()->message_factory->GetPrototype(
self->message->GetDescriptor());
self->message = prototype->New();
self->owner.reset(self->message); self->owner.reset(self->message);
// Cascade the new owner to eventual children: even if this message is // Cascade the new owner to eventual children: even if this message is
// empty, some submessages or repeated containers might exist already. // empty, some submessages or repeated containers might exist already.
@ -1190,15 +1224,19 @@ CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) {
// The __new__ method of Message classes. // The __new__ method of Message classes.
// Creates a new C++ message and takes ownership. // Creates a new C++ message and takes ownership.
static PyObject* New(PyTypeObject* type, static PyObject* New(PyTypeObject* cls,
PyObject* unused_args, PyObject* unused_kwargs) { PyObject* unused_args, PyObject* unused_kwargs) {
PyMessageMeta* type = CheckMessageClass(cls);
if (type == NULL) {
return NULL;
}
// Retrieve the message descriptor and the default instance (=prototype). // Retrieve the message descriptor and the default instance (=prototype).
const Descriptor* message_descriptor = GetMessageDescriptor(type); const Descriptor* message_descriptor = type->message_descriptor;
if (message_descriptor == NULL) { if (message_descriptor == NULL) {
return NULL; return NULL;
} }
const Message* default_message = const Message* default_message = type->py_descriptor_pool->message_factory
GetDescriptorPool()->message_factory->GetPrototype(message_descriptor); ->GetPrototype(message_descriptor);
if (default_message == NULL) { if (default_message == NULL) {
PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
return NULL; return NULL;
@ -1528,7 +1566,7 @@ int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) {
Message* ReleaseMessage(CMessage* self, Message* ReleaseMessage(CMessage* self,
const Descriptor* descriptor, const Descriptor* descriptor,
const FieldDescriptor* field_descriptor) { const FieldDescriptor* field_descriptor) {
MessageFactory* message_factory = GetDescriptorPool()->message_factory; MessageFactory* message_factory = GetFactoryForMessage(self);
Message* released_message = self->message->GetReflection()->ReleaseMessage( Message* released_message = self->message->GetReflection()->ReleaseMessage(
self->message, field_descriptor, message_factory); self->message, field_descriptor, message_factory);
// ReleaseMessage will return NULL which differs from // ReleaseMessage will return NULL which differs from
@ -1883,8 +1921,8 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
AssureWritable(self); AssureWritable(self);
io::CodedInputStream input( io::CodedInputStream input(
reinterpret_cast<const uint8*>(data), data_length); reinterpret_cast<const uint8*>(data), data_length);
input.SetExtensionRegistry(GetDescriptorPool()->pool, PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
GetDescriptorPool()->message_factory); input.SetExtensionRegistry(pool->pool, pool->message_factory);
bool success = self->message->MergePartialFromCodedStream(&input); bool success = self->message->MergePartialFromCodedStream(&input);
if (success) { if (success) {
return PyInt_FromLong(input.CurrentPosition()); return PyInt_FromLong(input.CurrentPosition());
@ -1907,11 +1945,6 @@ static PyObject* ByteSize(CMessage* self, PyObject* args) {
static PyObject* RegisterExtension(PyObject* cls, static PyObject* RegisterExtension(PyObject* cls,
PyObject* extension_handle) { PyObject* extension_handle) {
ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
if (message_descriptor == NULL) {
return NULL;
}
const FieldDescriptor* descriptor = const FieldDescriptor* descriptor =
GetExtensionDescriptor(extension_handle); GetExtensionDescriptor(extension_handle);
if (descriptor == NULL) { if (descriptor == NULL) {
@ -1920,13 +1953,6 @@ static PyObject* RegisterExtension(PyObject* cls,
const Descriptor* cmessage_descriptor = GetMessageDescriptor( const Descriptor* cmessage_descriptor = GetMessageDescriptor(
reinterpret_cast<PyTypeObject*>(cls)); reinterpret_cast<PyTypeObject*>(cls));
if (cmessage_descriptor != descriptor->containing_type()) {
if (PyObject_SetAttrString(extension_handle, "containing_type",
message_descriptor) < 0) {
return NULL;
}
}
ScopedPyObjectPtr extensions_by_name( ScopedPyObjectPtr extensions_by_name(
PyObject_GetAttr(cls, k_extensions_by_name)); PyObject_GetAttr(cls, k_extensions_by_name));
if (extensions_by_name == NULL) { if (extensions_by_name == NULL) {
@ -2050,7 +2076,8 @@ static PyObject* ListFields(CMessage* self) {
// TODO(amauryfa): consider building the class on the fly! // TODO(amauryfa): consider building the class on the fly!
if (fields[i]->message_type() != NULL && if (fields[i]->message_type() != NULL &&
cdescriptor_pool::GetMessageClass( cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), fields[i]->message_type()) == NULL) { GetDescriptorPoolForMessage(self),
fields[i]->message_type()) == NULL) {
PyErr_Clear(); PyErr_Clear();
continue; continue;
} }
@ -2207,7 +2234,9 @@ PyObject* InternalGetScalar(const Message* message,
message->GetReflection()->GetUnknownFields(*message); message->GetReflection()->GetUnknownFields(*message);
for (int i = 0; i < unknown_field_set.field_count(); ++i) { for (int i = 0; i < unknown_field_set.field_count(); ++i) {
if (unknown_field_set.field(i).number() == if (unknown_field_set.field(i).number() ==
field_descriptor->number()) { field_descriptor->number() &&
unknown_field_set.field(i).type() ==
google::protobuf::UnknownField::TYPE_VARINT) {
result = PyInt_FromLong(unknown_field_set.field(i).varint()); result = PyInt_FromLong(unknown_field_set.field(i).varint());
break; break;
} }
@ -2233,11 +2262,12 @@ PyObject* InternalGetScalar(const Message* message,
PyObject* InternalGetSubMessage( PyObject* InternalGetSubMessage(
CMessage* self, const FieldDescriptor* field_descriptor) { CMessage* self, const FieldDescriptor* field_descriptor) {
const Reflection* reflection = self->message->GetReflection(); const Reflection* reflection = self->message->GetReflection();
PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
const Message& sub_message = reflection->GetMessage( const Message& sub_message = reflection->GetMessage(
*self->message, field_descriptor, GetDescriptorPool()->message_factory); *self->message, field_descriptor, pool->message_factory);
PyObject *message_class = cdescriptor_pool::GetMessageClass( PyObject *message_class = cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), field_descriptor->message_type()); pool, field_descriptor->message_type());
if (message_class == NULL) { if (message_class == NULL) {
return NULL; return NULL;
} }
@ -2560,7 +2590,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
const FieldDescriptor* value_type = entry_type->FindFieldByName("value"); const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject* value_class = cdescriptor_pool::GetMessageClass( PyObject* value_class = cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), value_type->message_type()); GetDescriptorPoolForMessage(self), value_type->message_type());
if (value_class == NULL) { if (value_class == NULL) {
return NULL; return NULL;
} }
@ -2583,7 +2613,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
PyObject* py_container = NULL; PyObject* py_container = NULL;
if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject *message_class = cdescriptor_pool::GetMessageClass( PyObject *message_class = cdescriptor_pool::GetMessageClass(
GetDescriptorPool(), field_descriptor->message_type()); GetDescriptorPoolForMessage(self), field_descriptor->message_type());
if (message_class == NULL) { if (message_class == NULL) {
return NULL; return NULL;
} }
@ -2924,9 +2954,10 @@ bool InitProto2MessageModule(PyObject *m) {
// Expose the DescriptorPool used to hold all descriptors added from generated // Expose the DescriptorPool used to hold all descriptors added from generated
// pb2.py files. // pb2.py files.
Py_INCREF(GetDescriptorPool()); // PyModule_AddObject steals a reference. // PyModule_AddObject steals a reference.
PyModule_AddObject( Py_INCREF(GetDefaultDescriptorPool());
m, "default_pool", reinterpret_cast<PyObject*>(GetDescriptorPool())); PyModule_AddObject(m, "default_pool",
reinterpret_cast<PyObject*>(GetDefaultDescriptorPool()));
// This implementation provides full Descriptor types, we advertise it so that // This implementation provides full Descriptor types, we advertise it so that
// descriptor.py can use them in replacement of the Python classes. // descriptor.py can use them in replacement of the Python classes.

@ -49,12 +49,15 @@ class Message;
class Reflection; class Reflection;
class FieldDescriptor; class FieldDescriptor;
class Descriptor; class Descriptor;
class DescriptorPool;
class MessageFactory;
using internal::shared_ptr; using internal::shared_ptr;
namespace python { namespace python {
struct ExtensionDict; struct ExtensionDict;
struct PyDescriptorPool;
typedef struct CMessage { typedef struct CMessage {
PyObject_HEAD; PyObject_HEAD;
@ -220,6 +223,16 @@ PyObject* FindInitializationErrors(CMessage* self);
int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner); int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
int AssureWritable(CMessage* self); int AssureWritable(CMessage* self);
// Returns the "best" DescriptorPool for the given message.
// This is often equivalent to message.DESCRIPTOR.pool, but not always, when
// the message class was created from a MessageFactory using a custom pool which
// uses the generated pool as an underlay.
//
// The returned pool is suitable for finding fields and building submessages,
// even in the case of extensions.
PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
} // namespace cmessage } // namespace cmessage

@ -60,6 +60,7 @@ Example usage:
""" """
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool from google.protobuf import descriptor_pool
@ -72,6 +73,31 @@ class SymbolDatabase(object):
buffer types used within a program. buffer types used within a program.
""" """
# pylint: disable=protected-access
if _descriptor._USE_C_DESCRIPTORS:
def __new__(cls):
raise TypeError("Instances of SymbolDatabase cannot be created")
@classmethod
def _CreateDefaultDatabase(cls):
self = object.__new__(cls) # Bypass the __new__ above.
# Don't call __init__() and initialize here.
self._symbols = {}
self._symbols_by_file = {}
# As of today all descriptors are registered and retrieved from
# _message.default_pool (see FileDescriptor.__new__), so it's not
# necessary to use another pool.
self.pool = _descriptor._message.default_pool
return self
# pylint: enable=protected-access
else:
@classmethod
def _CreateDefaultDatabase(cls):
return cls()
def __init__(self): def __init__(self):
"""Constructor.""" """Constructor."""
@ -177,7 +203,7 @@ class SymbolDatabase(object):
result.update(self._symbols_by_file[f]) result.update(self._symbols_by_file[f])
return result return result
_DEFAULT = SymbolDatabase() _DEFAULT = SymbolDatabase._CreateDefaultDatabase()
def Default(): def Default():

@ -27,6 +27,7 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Encoding related utilities.""" """Encoding related utilities."""
import re import re

@ -28,9 +28,17 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2007 Google Inc. All Rights Reserved. """Contains routines for printing protocol messages in text format.
"""Contains routines for printing protocol messages in text format.""" Simple usage example:
# Create a proto object and serialize it to a text proto string.
message = my_proto_pb2.MyMessage(foo='bar')
text_proto = text_format.MessageToString(message)
# Parse a text proto string.
message = text_format.Parse(text_proto, my_proto_pb2.MyMessage())
"""
__author__ = 'kenton@google.com (Kenton Varda)' __author__ = 'kenton@google.com (Kenton Varda)'

@ -88,6 +88,15 @@ def GenerateUnittestProtos():
generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False) generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False)
generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False) generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False)
generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False) generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False)
# Move the well-known-types proto to required when they are no longer only
# required by json format tests.
generate_proto("../src/google/protobuf/timestamp.proto", False)
generate_proto("../src/google/protobuf/duration.proto", False)
generate_proto("../src/google/protobuf/wrappers.proto", False)
generate_proto("../src/google/protobuf/struct.proto", False)
generate_proto("../src/google/protobuf/any.proto", False)
generate_proto("../src/google/protobuf/field_mask.proto", False)
generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False)
generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False) generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False)
generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False) generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
generate_proto("google/protobuf/internal/factory_test1.proto", False) generate_proto("google/protobuf/internal/factory_test1.proto", False)

@ -2,7 +2,8 @@
envlist = envlist =
# cpp implementation on py34 is currently broken due to # cpp implementation on py34 is currently broken due to
# changes introduced by http://bugs.python.org/issue22079. # changes introduced by http://bugs.python.org/issue22079.
py{26,27,33,34}-{cpp,python} # py26 is currently broken due to the json_format
py{27,33,34}-{cpp,python}
[testenv] [testenv]
usedevelop=true usedevelop=true

@ -43,6 +43,7 @@ string GetTypeUrl(const Descriptor* message) {
const char kAnyFullTypeName[] = "google.protobuf.Any"; const char kAnyFullTypeName[] = "google.protobuf.Any";
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/"; const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
: type_url_(type_url), value_(value) { : type_url_(type_url), value_(value) {
@ -70,11 +71,17 @@ bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
} }
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
const int prefix_len = strlen(kTypeGoogleApisComPrefix); static const char* prefix[] = {
if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) { kTypeGoogleApisComPrefix,
full_type_name->assign(type_url.data() + prefix_len, kTypeGoogleProdComPrefix
type_url.size() - prefix_len); };
return true; for (int i = 0; i < 2; i++) {
const int prefix_len = strlen(prefix[i]);
if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) {
full_type_name->assign(type_url.data() + prefix_len,
type_url.size() - prefix_len);
return true;
}
} }
return false; return false;
} }

@ -70,6 +70,7 @@ class LIBPROTOBUF_EXPORT AnyMetadata {
extern const char kAnyFullTypeName[]; // "google.protobuf.Any". extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/". extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
// Get the proto type name from Any::type_url value. For example, passing // Get the proto type name from Any::type_url value. For example, passing
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in // "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in

@ -38,17 +38,17 @@ namespace google {
namespace protobuf { namespace protobuf {
google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_; google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
#ifdef PROTOBUF_USE_DLLS #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
Arena::ThreadCache& Arena::thread_cache() {
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
return thread_cache_;
}
#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
Arena::ThreadCache& Arena::thread_cache() { Arena::ThreadCache& Arena::thread_cache() {
static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ = static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
new internal::ThreadLocalStorage<ThreadCache>(); new internal::ThreadLocalStorage<ThreadCache>();
return *thread_cache_->Get(); return *thread_cache_->Get();
} }
#elif defined(PROTOBUF_USE_DLLS)
Arena::ThreadCache& Arena::thread_cache() {
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
return thread_cache_;
}
#else #else
GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL }; GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
#endif #endif

@ -38,7 +38,16 @@
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
#include <google/protobuf/stubs/type_traits.h> #include <google/protobuf/stubs/type_traits.h>
#endif #endif
#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
#include <exception>
#include <typeinfo> #include <typeinfo>
namespace std {
using type_info = ::type_info;
}
#else
#include <typeinfo>
#endif
#include <google/protobuf/stubs/atomic_sequence_num.h> #include <google/protobuf/stubs/atomic_sequence_num.h>
#include <google/protobuf/stubs/atomicops.h> #include <google/protobuf/stubs/atomicops.h>
@ -533,15 +542,15 @@ class LIBPROTOBUF_EXPORT Arena {
static const size_t kHeaderSize = sizeof(Block); static const size_t kHeaderSize = sizeof(Block);
static google::protobuf::internal::SequenceNumber lifecycle_id_generator_; static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
#ifdef PROTOBUF_USE_DLLS #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// Thread local variables cannot be exposed through DLL interface but we can
// wrap them in static functions.
static ThreadCache& thread_cache();
#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
// local storage class we implemented. // local storage class we implemented.
// iOS also does not support the GOOGLE_THREAD_LOCAL keyword. // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
static ThreadCache& thread_cache(); static ThreadCache& thread_cache();
#elif defined(PROTOBUF_USE_DLLS)
// Thread local variables cannot be exposed through DLL interface but we can
// wrap them in static functions.
static ThreadCache& thread_cache();
#else #else
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_; static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
static ThreadCache& thread_cache() { return thread_cache_; } static ThreadCache& thread_cache() { return thread_cache_; }
@ -581,11 +590,13 @@ class LIBPROTOBUF_EXPORT Arena {
template<typename U> template<typename U>
static double DestructorSkippable(...); static double DestructorSkippable(...);
// The raw_skippable_value const bool variable is separated from the typedef
// line below as a work-around of an NVCC 7.0 (and earlier) compiler bug.
static const bool raw_skippable_value =
sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) ==
sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true;
// This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
typedef google::protobuf::internal::integral_constant<bool, typedef google::protobuf::internal::integral_constant<bool, raw_skippable_value> type;
sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) ==
sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true>
type;
static const type value; static const type value;
}; };

@ -362,7 +362,7 @@ TEST(ArenaTest, ReleaseMessage) {
Arena arena; Arena arena;
TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
arena_message->mutable_optional_nested_message()->set_bb(118); arena_message->mutable_optional_nested_message()->set_bb(118);
scoped_ptr<TestAllTypes::NestedMessage> nested( google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
arena_message->release_optional_nested_message()); arena_message->release_optional_nested_message());
EXPECT_EQ(118, nested->bb()); EXPECT_EQ(118, nested->bb());
@ -383,7 +383,7 @@ TEST(ArenaTest, ReleaseString) {
Arena arena; Arena arena;
TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
arena_message->set_optional_string("hello"); arena_message->set_optional_string("hello");
scoped_ptr<string> released_str( google::protobuf::scoped_ptr<string> released_str(
arena_message->release_optional_string()); arena_message->release_optional_string());
EXPECT_EQ("hello", *released_str); EXPECT_EQ("hello", *released_str);

@ -63,13 +63,13 @@
#include <google/protobuf/testing/googletest.h> #include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace compiler {
// Disable the whole test when we use tcmalloc for "draconian" heap checks, in // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
// which case tcmalloc will print warnings that fail the plugin tests. // which case tcmalloc will print warnings that fail the plugin tests.
#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
namespace google {
namespace protobuf {
namespace compiler {
#if defined(_WIN32) #if defined(_WIN32)
#ifndef STDIN_FILENO #ifndef STDIN_FILENO
@ -1800,8 +1800,8 @@ TEST_F(EncodeDecodeTest, ProtoParseError) {
} // anonymous namespace } // anonymous namespace
#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
} // namespace compiler } // namespace compiler
} // namespace protobuf } // namespace protobuf
#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
} // namespace google } // namespace google

@ -66,7 +66,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["wrapper"] = "EntryWrapper"; (*variables)["wrapper"] = "EntryWrapper";
break; break;
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
(*variables)["val_cpp"] = ClassName(val->enum_type(), false); (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
(*variables)["wrapper"] = "EnumEntryWrapper"; (*variables)["wrapper"] = "EnumEntryWrapper";
break; break;
default: default:
@ -200,7 +200,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
printer->Print(variables_, printer->Print(variables_,
"(*mutable_$name$())[entry->key()] =\n" "(*mutable_$name$())[entry->key()] =\n"
" static_cast<$val_cpp$>(*entry->mutable_value());\n"); " static_cast< $val_cpp$ >(*entry->mutable_value());\n");
break; break;
default: default:
printer->Print(variables_, printer->Print(variables_,
@ -215,7 +215,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" DO_(entry->ParseFromString(data));\n" " DO_(entry->ParseFromString(data));\n"
" if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
" (*mutable_$name$())[entry->key()] =\n" " (*mutable_$name$())[entry->key()] =\n"
" static_cast<$val_cpp$>(*entry->mutable_value());\n" " static_cast< $val_cpp$ >(*entry->mutable_value());\n"
" } else {\n"); " } else {\n");
if (HasDescriptorMethods(descriptor_->file())) { if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(variables_, printer->Print(variables_,

@ -350,7 +350,7 @@ void CollectMapInfo(const Descriptor* descriptor,
(*variables)["val"] = FieldMessageTypeName(val); (*variables)["val"] = FieldMessageTypeName(val);
break; break;
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
(*variables)["val"] = ClassName(val->enum_type(), false); (*variables)["val"] = ClassName(val->enum_type(), true);
break; break;
default: default:
(*variables)["val"] = PrimitiveTypeName(val->cpp_type()); (*variables)["val"] = PrimitiveTypeName(val->cpp_type());

@ -299,7 +299,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n"); "if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) { if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_, printer->Print(variables_,
" unknownFields.mergeVarintField($number$, rawValue);\n"); " super.mergeVarintField($number$, rawValue);\n");
} }
printer->Print(variables_, printer->Print(variables_,
"} else {\n" "} else {\n"
@ -492,7 +492,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n"); "if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) { if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_, printer->Print(variables_,
" unknownFields.mergeVarintField($number$, rawValue);\n"); " super.mergeVarintField($number$, rawValue);\n");
} }
printer->Print(variables_, printer->Print(variables_,
"} else {\n" "} else {\n"
@ -850,7 +850,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n"); "if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) { if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_, printer->Print(variables_,
" unknownFields.mergeVarintField($number$, rawValue);\n"); " super.mergeVarintField($number$, rawValue);\n");
} }
printer->Print(variables_, printer->Print(variables_,
"} else {\n" "} else {\n"

@ -405,7 +405,7 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print( printer->Print(
variables_, variables_,
"if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
" unknownFields.mergeLengthDelimitedField($number$, bytes);\n" " super.mergeLengthDelimitedField($number$, bytes);\n"
"} else {\n" "} else {\n"
" $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
"}\n"); "}\n");

@ -1029,12 +1029,6 @@ GenerateParsingConstructor(io::Printer* printer) {
"bit_field_name", GetBitFieldName(i)); "bit_field_name", GetBitFieldName(i));
} }
if (PreserveUnknownFields(descriptor_)) {
printer->Print(
"com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
" com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
}
printer->Print( printer->Print(
"try {\n"); "try {\n");
printer->Indent(); printer->Indent();
@ -1056,13 +1050,10 @@ GenerateParsingConstructor(io::Printer* printer) {
if (PreserveUnknownFields(descriptor_)) { if (PreserveUnknownFields(descriptor_)) {
if (descriptor_->extension_range_count() > 0) { if (descriptor_->extension_range_count() > 0) {
// Lite runtime directly invokes parseUnknownField to reduce method
// counts.
printer->Print( printer->Print(
"default: {\n" "default: {\n"
" if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" " if (!parseUnknownField(getDefaultInstanceForType(),\n"
" input, unknownFields,\n" " input, extensionRegistry, tag)) {\n"
" extensionRegistry, tag)) {\n"
" done = true;\n" // it's an endgroup tag " done = true;\n" // it's an endgroup tag
" }\n" " }\n"
" break;\n" " break;\n"
@ -1070,8 +1061,7 @@ GenerateParsingConstructor(io::Printer* printer) {
} else { } else {
printer->Print( printer->Print(
"default: {\n" "default: {\n"
" if (!parseUnknownField(input, unknownFields,\n" " if (!parseUnknownField(tag, input)) {\n"
" extensionRegistry, tag)) {\n"
" done = true;\n" // it's an endgroup tag " done = true;\n" // it's an endgroup tag
" }\n" " }\n"
" break;\n" " break;\n"
@ -1146,16 +1136,8 @@ GenerateParsingConstructor(io::Printer* printer) {
field_generators_.get(field).GenerateParsingDoneCode(printer); field_generators_.get(field).GenerateParsingDoneCode(printer);
} }
if (PreserveUnknownFields(descriptor_)) { printer->Print(
// Make unknown fields immutable. "doneParsing();\n");
printer->Print("this.unknownFields = unknownFields.build();\n");
}
if (descriptor_->extension_range_count() > 0) {
// Make extensions immutable.
printer->Print(
"makeExtensionsImmutable(extensions);\n");
}
printer->Outdent(); printer->Outdent();
printer->Outdent(); printer->Outdent();

@ -993,6 +993,9 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
// We intentionally pass field_location rather than location here, since // We intentionally pass field_location rather than location here, since
// the default value is not actually an option. // the default value is not actually an option.
DO(ParseDefaultAssignment(field, field_location, containing_file)); DO(ParseDefaultAssignment(field, field_location, containing_file));
} else if (LookingAt("json_name")) {
// Like default value, this "json_name" is not an actual option.
DO(ParseJsonName(field, field_location, containing_file));
} else { } else {
DO(ParseOption(field->mutable_options(), location, DO(ParseOption(field->mutable_options(), location,
containing_file, OPTION_ASSIGNMENT)); containing_file, OPTION_ASSIGNMENT));
@ -1140,6 +1143,28 @@ bool Parser::ParseDefaultAssignment(
return true; return true;
} }
bool Parser::ParseJsonName(
FieldDescriptorProto* field,
const LocationRecorder& field_location,
const FileDescriptorProto* containing_file) {
if (field->has_json_name()) {
AddError("Already set option \"json_name\".");
field->clear_json_name();
}
DO(Consume("json_name"));
DO(Consume("="));
LocationRecorder location(field_location,
FieldDescriptorProto::kJsonNameFieldNumber);
location.RecordLegacyLocation(
field, DescriptorPool::ErrorCollector::OPTION_VALUE);
DO(ConsumeString(field->mutable_json_name(),
"Expected string for JSON name."));
return true;
}
bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option, bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
const LocationRecorder& part_location, const LocationRecorder& part_location,
const FileDescriptorProto* containing_file) { const FileDescriptorProto* containing_file) {

@ -439,6 +439,10 @@ class LIBPROTOBUF_EXPORT Parser {
const LocationRecorder& field_location, const LocationRecorder& field_location,
const FileDescriptorProto* containing_file); const FileDescriptorProto* containing_file);
bool ParseJsonName(FieldDescriptorProto* field,
const LocationRecorder& field_location,
const FileDescriptorProto* containing_file);
enum OptionStyle { enum OptionStyle {
OPTION_ASSIGNMENT, // just "name = value" OPTION_ASSIGNMENT, // just "name = value"
OPTION_STATEMENT // "option name = value;" OPTION_STATEMENT // "option name = value;"

@ -452,6 +452,20 @@ TEST_F(ParseMessageTest, FieldDefaults) {
#undef ETC #undef ETC
} }
TEST_F(ParseMessageTest, FieldJsonName) {
ExpectParsesTo(
"message TestMessage {\n"
" optional string foo = 1 [json_name = \"@type\"];\n"
"}\n",
"message_type {"
" name: \"TestMessage\""
" field {\n"
" name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
" json_name: \"@type\"\n"
" }\n"
"}\n");
}
TEST_F(ParseMessageTest, FieldOptions) { TEST_F(ParseMessageTest, FieldOptions) {
ExpectParsesTo( ExpectParsesTo(
"message TestMessage {\n" "message TestMessage {\n"
@ -1126,6 +1140,22 @@ TEST_F(ParseErrorTest, DefaultValueTooLarge) {
"6:36: Integer out of range.\n"); "6:36: Integer out of range.\n");
} }
TEST_F(ParseErrorTest, JsonNameNotString) {
ExpectHasErrors(
"message TestMessage {\n"
" optional string foo = 1 [json_name=1];\n"
"}\n",
"1:37: Expected string for JSON name.\n");
}
TEST_F(ParseErrorTest, DuplicateJsonName) {
ExpectHasErrors(
"message TestMessage {\n"
" optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
"}\n",
"1:41: Already set option \"json_name\".\n");
}
TEST_F(ParseErrorTest, EnumValueOutOfRange) { TEST_F(ParseErrorTest, EnumValueOutOfRange) {
ExpectHasErrors( ExpectHasErrors(
"enum TestEnum {\n" "enum TestEnum {\n"

@ -28,6 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#PY25 compatible generated code for GAE.
// Copyright 2007 Google Inc. All Rights Reserved. // Copyright 2007 Google Inc. All Rights Reserved.
// Author: robinson@google.com (Will Robinson) // Author: robinson@google.com (Will Robinson)
// //
@ -166,6 +167,7 @@ void PrintTopBoilerplate(
printer->Print( printer->Print(
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n" "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"# source: $filename$\n" "# source: $filename$\n"
"\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))" //##PY25
"\n", "\n",
"filename", file->name()); "filename", file->name());
if (HasTopLevelEnums(file)) { if (HasTopLevelEnums(file)) {
@ -257,9 +259,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
return SimpleItoa(field.default_value_enum()->number()); return SimpleItoa(field.default_value_enum()->number());
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
return "b\"" + CEscape(field.default_value_string()) + //##!PY25 return "b\"" + CEscape(field.default_value_string()) +
(field.type() != FieldDescriptor::TYPE_STRING ? "\"" : //##!PY25 (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
"\".decode('utf-8')"); //##!PY25 "\".decode('utf-8')");
return "_b(\"" + CEscape(field.default_value_string()) + //##PY25
(field.type() != FieldDescriptor::TYPE_STRING ? "\")" : //##PY25
"\").decode('utf-8')"); //##PY25
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
return "None"; return "None";
} }
@ -385,7 +390,8 @@ void Generator::PrintFileDescriptor() const {
printer_->Print(m, file_descriptor_template); printer_->Print(m, file_descriptor_template);
printer_->Indent(); printer_->Indent();
printer_->Print( printer_->Print(
"serialized_pb=b'$value$'\n", //##!PY25 "serialized_pb=b'$value$'\n",
"serialized_pb=_b('$value$')\n", //##PY25
"value", strings::CHexEscape(file_descriptor_serialized_)); "value", strings::CHexEscape(file_descriptor_serialized_));
if (file_->dependency_count() != 0) { if (file_->dependency_count() != 0) {
printer_->Print(",\ndependencies=["); printer_->Print(",\ndependencies=[");
@ -1029,8 +1035,10 @@ string Generator::OptionsValue(
return "None"; return "None";
} else { } else {
string full_class_name = "descriptor_pb2." + class_name; string full_class_name = "descriptor_pb2." + class_name;
return "_descriptor._ParseOptions(" + full_class_name + "(), b'" //##!PY25 return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
+ CEscape(serialized_options)+ "')"; //##!PY25 + CEscape(serialized_options)+ "')";
return "_descriptor._ParseOptions(" + full_class_name + "(), _b('" //##PY25
+ CEscape(serialized_options)+ "'))"; //##PY25
} }
} }

@ -34,6 +34,10 @@
#include <google/protobuf/stubs/hash.h> #include <google/protobuf/stubs/hash.h>
#include <map> #include <map>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -1726,6 +1730,20 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
} }
} }
void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const {
if (message_type_count() != proto->message_type_size() ||
extension_count() != proto->extension_size()) {
GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
return;
}
for (int i = 0; i < message_type_count(); i++) {
message_type(i)->CopyJsonNameTo(proto->mutable_message_type(i));
}
for (int i = 0; i < extension_count(); i++) {
extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
}
}
void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const { void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
if (source_code_info_ && if (source_code_info_ &&
source_code_info_ != &SourceCodeInfo::default_instance()) { source_code_info_ != &SourceCodeInfo::default_instance()) {
@ -1770,9 +1788,30 @@ void Descriptor::CopyTo(DescriptorProto* proto) const {
} }
} }
void Descriptor::CopyJsonNameTo(DescriptorProto* proto) const {
if (field_count() != proto->field_size() ||
nested_type_count() != proto->nested_type_size() ||
extension_count() != proto->extension_size()) {
GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
return;
}
for (int i = 0; i < field_count(); i++) {
field(i)->CopyJsonNameTo(proto->mutable_field(i));
}
for (int i = 0; i < nested_type_count(); i++) {
nested_type(i)->CopyJsonNameTo(proto->mutable_nested_type(i));
}
for (int i = 0; i < extension_count(); i++) {
extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
}
}
void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
proto->set_name(name()); proto->set_name(name());
proto->set_number(number()); proto->set_number(number());
if (has_json_name_) {
proto->set_json_name(json_name());
}
// Some compilers do not allow static_cast directly between two enum types, // Some compilers do not allow static_cast directly between two enum types,
// so we must cast to int first. // so we must cast to int first.
@ -1819,6 +1858,10 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
} }
} }
void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
proto->set_json_name(json_name());
}
void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const { void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
proto->set_name(name()); proto->set_name(name());
} }
@ -4136,6 +4179,14 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
tables_->AllocateString(ToCamelCase(proto.name(), tables_->AllocateString(ToCamelCase(proto.name(),
/* lower_first = */ true)); /* lower_first = */ true));
if (proto.has_json_name()) {
result->has_json_name_ = true;
result->json_name_ = tables_->AllocateString(proto.json_name());
} else {
result->has_json_name_ = false;
result->json_name_ = result->camelcase_name_;
}
// Some compilers do not allow static_cast directly between two enum types, // Some compilers do not allow static_cast directly between two enum types,
// so we must cast to int first. // so we must cast to int first.
result->type_ = static_cast<FieldDescriptor::Type>( result->type_ = static_cast<FieldDescriptor::Type>(
@ -5040,6 +5091,20 @@ void DescriptorBuilder::ValidateProto3(
} }
} }
static string ToLowercaseWithoutUnderscores(const string& name) {
string result;
for (int i = 0; i < name.size(); ++i) {
if (name[i] != '_') {
if (name[i] >= 'A' && name[i] <= 'Z') {
result.push_back(name[i] - 'A' + 'a');
} else {
result.push_back(name[i]);
}
}
}
return result;
}
void DescriptorBuilder::ValidateProto3Message( void DescriptorBuilder::ValidateProto3Message(
Descriptor* message, const DescriptorProto& proto) { Descriptor* message, const DescriptorProto& proto) {
for (int i = 0; i < message->nested_type_count(); ++i) { for (int i = 0; i < message->nested_type_count(); ++i) {
@ -5067,6 +5132,25 @@ void DescriptorBuilder::ValidateProto3Message(
DescriptorPool::ErrorCollector::OTHER, DescriptorPool::ErrorCollector::OTHER,
"MessageSet is not supported in proto3."); "MessageSet is not supported in proto3.");
} }
// In proto3, we reject field names if they conflict in camelCase.
// Note that we currently enforce a stricter rule: Field names must be
// unique after being converted to lowercase with underscores removed.
map<string, const FieldDescriptor*> name_to_field;
for (int i = 0; i < message->field_count(); ++i) {
string lowercase_name = ToLowercaseWithoutUnderscores(
message->field(i)->name());
if (name_to_field.find(lowercase_name) != name_to_field.end()) {
AddError(message->full_name(), proto,
DescriptorPool::ErrorCollector::OTHER,
"The JSON camcel-case name of field \"" +
message->field(i)->name() + "\" conflicts with field \"" +
name_to_field[lowercase_name]->name() + "\". This is not " +
"allowed in proto3.");
} else {
name_to_field[lowercase_name] = message->field(i);
}
}
} }
void DescriptorBuilder::ValidateProto3Field( void DescriptorBuilder::ValidateProto3Field(
@ -5602,7 +5686,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// First set the value on the UnknownFieldSet corresponding to the // First set the value on the UnknownFieldSet corresponding to the
// innermost message. // innermost message.
scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet()); google::protobuf::scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
if (!SetOptionValue(field, unknown_fields.get())) { if (!SetOptionValue(field, unknown_fields.get())) {
return false; // SetOptionValue() already added the error. return false; // SetOptionValue() already added the error.
} }
@ -5612,7 +5696,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
for (vector<const FieldDescriptor*>::reverse_iterator iter = for (vector<const FieldDescriptor*>::reverse_iterator iter =
intermediate_fields.rbegin(); intermediate_fields.rbegin();
iter != intermediate_fields.rend(); ++iter) { iter != intermediate_fields.rend(); ++iter) {
scoped_ptr<UnknownFieldSet> parent_unknown_fields(new UnknownFieldSet()); google::protobuf::scoped_ptr<UnknownFieldSet> parent_unknown_fields(
new UnknownFieldSet());
switch ((*iter)->type()) { switch ((*iter)->type()) {
case FieldDescriptor::TYPE_MESSAGE: { case FieldDescriptor::TYPE_MESSAGE: {
io::StringOutputStream outstr( io::StringOutputStream outstr(
@ -5998,7 +6083,7 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
} }
const Descriptor* type = option_field->message_type(); const Descriptor* type = option_field->message_type();
scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New()); google::protobuf::scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
GOOGLE_CHECK(dynamic.get() != NULL) GOOGLE_CHECK(dynamic.get() != NULL)
<< "Could not create an instance of " << option_field->DebugString(); << "Could not create an instance of " << option_field->DebugString();

@ -54,6 +54,10 @@
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__ #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
#define GOOGLE_PROTOBUF_DESCRIPTOR_H__ #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -111,8 +115,17 @@ class UnknownField;
// Defined in generated_message_reflection.h. // Defined in generated_message_reflection.h.
namespace internal { namespace internal {
class GeneratedMessageReflection; class GeneratedMessageReflection;
} } // namespace internal
// Defined in command_line_interface.cc
namespace compiler {
class CommandLineInterface;
} // namespace compiler
namespace descriptor_unittest {
class DescriptorTest;
} // namespace descriptor_unittest
// NB, all indices are zero-based. // NB, all indices are zero-based.
struct SourceLocation { struct SourceLocation {
@ -343,6 +356,12 @@ class LIBPROTOBUF_EXPORT Descriptor {
private: private:
typedef MessageOptions OptionsType; typedef MessageOptions OptionsType;
// Allows tests to test CopyTo(proto, true).
friend class ::google::protobuf::descriptor_unittest::DescriptorTest;
// Fill the json_name field of FieldDescriptorProto.
void CopyJsonNameTo(DescriptorProto* proto) const;
// Internal version of DebugString; controls the level of indenting for // Internal version of DebugString; controls the level of indenting for
// correct depth. Takes |options| to control debug-string options, and // correct depth. Takes |options| to control debug-string options, and
// |include_opening_clause| to indicate whether the "message ... " part of the // |include_opening_clause| to indicate whether the "message ... " part of the
@ -484,6 +503,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
const string& name() const; // Name of this field within the message. const string& name() const; // Name of this field within the message.
const string& full_name() const; // Fully-qualified name of the field. const string& full_name() const; // Fully-qualified name of the field.
const string& json_name() const; // JSON name of this field.
const FileDescriptor* file() const;// File in which this field was defined. const FileDescriptor* file() const;// File in which this field was defined.
bool is_extension() const; // Is this an extension field? bool is_extension() const; // Is this an extension field?
int number() const; // Declared tag number. int number() const; // Declared tag number.
@ -624,6 +644,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
private: private:
typedef FieldOptions OptionsType; typedef FieldOptions OptionsType;
// Fill the json_name field of FieldDescriptorProto.
void CopyJsonNameTo(FieldDescriptorProto* proto) const;
// See Descriptor::DebugString(). // See Descriptor::DebugString().
enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL }; enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL };
void DebugString(int depth, PrintLabelFlag print_label_flag, void DebugString(int depth, PrintLabelFlag print_label_flag,
@ -645,6 +668,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
const string* full_name_; const string* full_name_;
const string* lowercase_name_; const string* lowercase_name_;
const string* camelcase_name_; const string* camelcase_name_;
// Whether the user has specified the json_name field option in the .proto
// file.
bool has_json_name_;
// If has_json_name_ is true, it's the value specified by the user.
// Otherwise, it has the same value as lowercase_name_.
const string* json_name_;
const FileDescriptor* file_; const FileDescriptor* file_;
int number_; int number_;
Type type_; Type type_;
@ -1202,6 +1231,9 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
// Write the source code information of this FileDescriptor into the given // Write the source code information of this FileDescriptor into the given
// FileDescriptorProto. See CopyTo() above. // FileDescriptorProto. See CopyTo() above.
void CopySourceCodeInfoTo(FileDescriptorProto* proto) const; void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
// Fill the json_name field of FieldDescriptorProto for all fields. Can only
// be called after CopyTo().
void CopyJsonNameTo(FileDescriptorProto* proto) const;
// See Descriptor::DebugString(). // See Descriptor::DebugString().
string DebugString() const; string DebugString() const;
@ -1559,7 +1591,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
// This class contains a lot of hash maps with complicated types that // This class contains a lot of hash maps with complicated types that
// we'd like to keep out of the header. // we'd like to keep out of the header.
class Tables; class Tables;
scoped_ptr<Tables> tables_; google::protobuf::scoped_ptr<Tables> tables_;
bool enforce_dependencies_; bool enforce_dependencies_;
bool allow_unknown_; bool allow_unknown_;
@ -1618,6 +1650,7 @@ PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, json_name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)

@ -200,7 +200,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_),
-1); -1);
FieldDescriptorProto_descriptor_ = file->message_type(3); FieldDescriptorProto_descriptor_ = file->message_type(3);
static const int FieldDescriptorProto_offsets_[9] = { static const int FieldDescriptorProto_offsets_[10] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_),
@ -209,6 +209,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, json_name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_),
}; };
FieldDescriptorProto_reflection_ = FieldDescriptorProto_reflection_ =
@ -663,101 +664,102 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
"tobuf.DescriptorProto.ReservedRange\022\025\n\rr" "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
"eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005" "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005"
"start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang" "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang"
"e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024FieldD" "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\274\005\n\024FieldD"
"escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003" "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003"
" \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi" " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi"
"eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*" "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*"
".google.protobuf.FieldDescriptorProto.Ty" ".google.protobuf.FieldDescriptorProto.Ty"
"pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022" "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022"
"\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t " "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t "
"\001(\005\022.\n\007options\030\010 \001(\0132\035.google.protobuf.F" "\001(\005\022\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001(\0132"
"ieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n" "\035.google.protobuf.FieldOptions\"\266\002\n\004Type\022"
"\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UI" "\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE"
"NT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006" "_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020"
"\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYP" "\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n"
"E_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSA" "\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GR"
"GE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n" "OUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022"
"\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_" "\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_"
"SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT" "SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI"
"64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LAB" "NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE"
"EL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n\024One" "L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE"
"ofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023Enum" "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004"
"DescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002" "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na"
" \003(\0132).google.protobuf.EnumValueDescript" "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu"
"orProto\022-\n\007options\030\003 \001(\0132\034.google.protob" "f.EnumValueDescriptorProto\022-\n\007options\030\003 "
"uf.EnumOptions\"l\n\030EnumValueDescriptorPro" "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu"
"to\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007opti" "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n"
"ons\030\003 \001(\0132!.google.protobuf.EnumValueOpt" "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr"
"ions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004name\030" "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr"
"\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.protobuf." "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013"
"MethodDescriptorProto\0220\n\007options\030\003 \001(\0132\037" "2&.google.protobuf.MethodDescriptorProto"
".google.protobuf.ServiceOptions\"\301\001\n\025Meth" "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv"
"odDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput" "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004"
"_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007opti" "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output"
"ons\030\004 \001(\0132\036.google.protobuf.MethodOption" "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr"
"s\022\037\n\020client_streaming\030\005 \001(\010:\005false\022\037\n\020se" "otobuf.MethodOptions\022\037\n\020client_streaming"
"rver_streaming\030\006 \001(\010:\005false\"\252\005\n\013FileOpti" "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:"
"ons\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_" "\005false\"\252\005\n\013FileOptions\022\024\n\014java_package\030\001"
"classname\030\010 \001(\t\022\"\n\023java_multiple_files\030\n" " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja"
" \001(\010:\005false\022,\n\035java_generate_equals_and_" "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g"
"hash\030\024 \001(\010:\005false\022%\n\026java_string_check_u" "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026"
"tf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001(\0162)" "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o"
".google.protobuf.FileOptions.OptimizeMod" "ptimize_for\030\t \001(\0162).google.protobuf.File"
"e:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_gener" "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag"
"ic_services\030\020 \001(\010:\005false\022$\n\025java_generic" "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa"
"_services\030\021 \001(\010:\005false\022\"\n\023py_generic_ser" "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals"
"vices\030\022 \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005" "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n"
"false\022\037\n\020cc_enable_arenas\030\037 \001(\010:\005false\022\031" "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar"
"\n\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_name" "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$"
"space\030% \001(\t\022\'\n\037javanano_use_deprecated_p" " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022\'\n\037javana"
"ackage\030& \001(\010\022C\n\024uninterpreted_option\030\347\007 " "no_use_deprecated_package\030& \001(\010\022C\n\024unint"
"\003(\0132$.google.protobuf.UninterpretedOptio" "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
"n\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZ" ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005"
"E\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016Mes" "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003"
"sageOptions\022&\n\027message_set_wire_format\030\001" "*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027messag"
" \001(\010:\005false\022.\n\037no_standard_descriptor_ac" "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta"
"cessor\030\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:" "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031"
"\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpret" "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007"
"ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
"erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptio" "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
"ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel" "\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g"
"dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?" "oogle.protobuf.FieldOptions.CType:\006STRIN"
"\n\006jstype\030\006 \001(\0162$.google.protobuf.FieldOp" "G\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$.goog"
"tions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005f" "le.protobuf.FieldOptions.JSType:\tJS_NORM"
"alse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030" "AL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecated\030\003 "
"\n \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 " "\001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024unint"
"\003(\0132$.google.protobuf.UninterpretedOptio" "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
"n\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRI" ".UninterpretedOption\"/\n\005CType\022\n\n\006STRING\020"
"NG_PIECE\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJ" "\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JSType\022"
"S_STRING\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n" "\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_NUMB"
"\013EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndep" "ER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow"
"recated\030\003 \001(\010:\005false\022C\n\024uninterpreted_op" "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022"
"tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google."
"tedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions" "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\""
"\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uninterpr" "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:"
"eted_option\030\347\007 \003(\0132$.google.protobuf.Uni" "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
"nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOp" "google.protobuf.UninterpretedOption*\t\010\350\007"
"tions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024unin" "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!"
"terpreted_option\030\347\007 \003(\0132$.google.protobu" " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
"f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMeth" "(\0132$.google.protobuf.UninterpretedOption"
"odOptions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024" "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat"
"uninterpreted_option\030\347\007 \003(\0132$.google.pro" "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030"
"tobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n" "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
"\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goo" "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022"
"gle.protobuf.UninterpretedOption.NamePar" ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp"
"t\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_" "retedOption.NamePart\022\030\n\020identifier_value"
"int_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 " "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne"
"\001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_valu" "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006"
"e\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010Name" " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_"
"Part\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030" "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002"
"\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003" "(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceCodeI"
"(\0132(.google.protobuf.SourceCodeInfo.Loca" "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf."
"tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s" "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004"
"pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022" "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead"
"\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de" "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030"
"tached_comments\030\006 \003(\tBX\n\023com.google.prot" "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t"
"obufB\020DescriptorProtosH\001Z\ndescriptor\242\002\003G" "BX\n\023com.google.protobufB\020DescriptorProto"
"PB\252\002\032Google.Protobuf.Reflection", 4991); "sH\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf."
"Reflection", 5010);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/descriptor.proto", &protobuf_RegisterTypes); "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
FileDescriptorSet::default_instance_ = new FileDescriptorSet(); FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@ -4109,6 +4111,7 @@ const int FieldDescriptorProto::kTypeNameFieldNumber;
const int FieldDescriptorProto::kExtendeeFieldNumber; const int FieldDescriptorProto::kExtendeeFieldNumber;
const int FieldDescriptorProto::kDefaultValueFieldNumber; const int FieldDescriptorProto::kDefaultValueFieldNumber;
const int FieldDescriptorProto::kOneofIndexFieldNumber; const int FieldDescriptorProto::kOneofIndexFieldNumber;
const int FieldDescriptorProto::kJsonNameFieldNumber;
const int FieldDescriptorProto::kOptionsFieldNumber; const int FieldDescriptorProto::kOptionsFieldNumber;
#endif // !_MSC_VER #endif // !_MSC_VER
@ -4141,6 +4144,7 @@ void FieldDescriptorProto::SharedCtor() {
extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
oneof_index_ = 0; oneof_index_ = 0;
json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
options_ = NULL; options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_)); ::memset(_has_bits_, 0, sizeof(_has_bits_));
} }
@ -4155,6 +4159,7 @@ void FieldDescriptorProto::SharedDtor() {
type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) { if (this != default_instance_) {
delete options_; delete options_;
} }
@ -4204,8 +4209,13 @@ void FieldDescriptorProto::Clear() {
} }
oneof_index_ = 0; oneof_index_ = 0;
} }
if (has_options()) { if (_has_bits_[8 / 32] & 768u) {
if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); if (has_json_name()) {
json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
if (has_options()) {
if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
}
} }
::memset(_has_bits_, 0, sizeof(_has_bits_)); ::memset(_has_bits_, 0, sizeof(_has_bits_));
if (_internal_metadata_.have_unknown_fields()) { if (_internal_metadata_.have_unknown_fields()) {
@ -4369,6 +4379,23 @@ bool FieldDescriptorProto::MergePartialFromCodedStream(
} else { } else {
goto handle_unusual; goto handle_unusual;
} }
if (input->ExpectTag(82)) goto parse_json_name;
break;
}
// optional string json_name = 10;
case 10: {
if (tag == 82) {
parse_json_name:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_json_name()));
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->json_name().data(), this->json_name().length(),
::google::protobuf::internal::WireFormat::PARSE,
"google.protobuf.FieldDescriptorProto.json_name");
} else {
goto handle_unusual;
}
if (input->ExpectAtEnd()) goto success; if (input->ExpectAtEnd()) goto success;
break; break;
} }
@ -4466,6 +4493,16 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output); ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
} }
// optional string json_name = 10;
if (has_json_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->json_name().data(), this->json_name().length(),
::google::protobuf::internal::WireFormat::SERIALIZE,
"google.protobuf.FieldDescriptorProto.json_name");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
10, this->json_name(), output);
}
if (_internal_metadata_.have_unknown_fields()) { if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields( ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output); unknown_fields(), output);
@ -4549,6 +4586,17 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target); target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target);
} }
// optional string json_name = 10;
if (has_json_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->json_name().data(), this->json_name().length(),
::google::protobuf::internal::WireFormat::SERIALIZE,
"google.protobuf.FieldDescriptorProto.json_name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
10, this->json_name(), target);
}
if (_internal_metadata_.have_unknown_fields()) { if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target); unknown_fields(), target);
@ -4616,13 +4664,22 @@ int FieldDescriptorProto::ByteSize() const {
} }
} }
// optional .google.protobuf.FieldOptions options = 8; if (_has_bits_[8 / 32] & 768u) {
if (has_options()) { // optional string json_name = 10;
total_size += 1 + if (has_json_name()) {
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( total_size += 1 +
*this->options_); ::google::protobuf::internal::WireFormatLite::StringSize(
} this->json_name());
}
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
*this->options_);
}
}
if (_internal_metadata_.have_unknown_fields()) { if (_internal_metadata_.have_unknown_fields()) {
total_size += total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@ -4679,6 +4736,10 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
} }
} }
if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
if (from.has_json_name()) {
set_has_json_name();
json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
}
if (from.has_options()) { if (from.has_options()) {
mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options()); mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options());
} }
@ -4721,6 +4782,7 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) {
extendee_.Swap(&other->extendee_); extendee_.Swap(&other->extendee_);
default_value_.Swap(&other->default_value_); default_value_.Swap(&other->default_value_);
std::swap(oneof_index_, other->oneof_index_); std::swap(oneof_index_, other->oneof_index_);
json_name_.Swap(&other->json_name_);
std::swap(options_, other->options_); std::swap(options_, other->options_);
std::swap(_has_bits_[0], other->_has_bits_[0]); std::swap(_has_bits_[0], other->_has_bits_[0]);
_internal_metadata_.Swap(&other->_internal_metadata_); _internal_metadata_.Swap(&other->_internal_metadata_);
@ -5048,15 +5110,68 @@ void FieldDescriptorProto::clear_oneof_index() {
// @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index) // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
} }
// optional string json_name = 10;
bool FieldDescriptorProto::has_json_name() const {
return (_has_bits_[0] & 0x00000100u) != 0;
}
void FieldDescriptorProto::set_has_json_name() {
_has_bits_[0] |= 0x00000100u;
}
void FieldDescriptorProto::clear_has_json_name() {
_has_bits_[0] &= ~0x00000100u;
}
void FieldDescriptorProto::clear_json_name() {
json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_json_name();
}
const ::std::string& FieldDescriptorProto::json_name() const {
// @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void FieldDescriptorProto::set_json_name(const ::std::string& value) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
}
void FieldDescriptorProto::set_json_name(const char* value) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
}
void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
}
::std::string* FieldDescriptorProto::mutable_json_name() {
set_has_json_name();
// @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
::std::string* FieldDescriptorProto::release_json_name() {
clear_has_json_name();
return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
if (json_name != NULL) {
set_has_json_name();
} else {
clear_has_json_name();
}
json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
}
// optional .google.protobuf.FieldOptions options = 8; // optional .google.protobuf.FieldOptions options = 8;
bool FieldDescriptorProto::has_options() const { bool FieldDescriptorProto::has_options() const {
return (_has_bits_[0] & 0x00000100u) != 0; return (_has_bits_[0] & 0x00000200u) != 0;
} }
void FieldDescriptorProto::set_has_options() { void FieldDescriptorProto::set_has_options() {
_has_bits_[0] |= 0x00000100u; _has_bits_[0] |= 0x00000200u;
} }
void FieldDescriptorProto::clear_has_options() { void FieldDescriptorProto::clear_has_options() {
_has_bits_[0] &= ~0x00000100u; _has_bits_[0] &= ~0x00000200u;
} }
void FieldDescriptorProto::clear_options() { void FieldDescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();

@ -1133,6 +1133,18 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
::google::protobuf::int32 oneof_index() const; ::google::protobuf::int32 oneof_index() const;
void set_oneof_index(::google::protobuf::int32 value); void set_oneof_index(::google::protobuf::int32 value);
// optional string json_name = 10;
bool has_json_name() const;
void clear_json_name();
static const int kJsonNameFieldNumber = 10;
const ::std::string& json_name() const;
void set_json_name(const ::std::string& value);
void set_json_name(const char* value);
void set_json_name(const char* value, size_t size);
::std::string* mutable_json_name();
::std::string* release_json_name();
void set_allocated_json_name(::std::string* json_name);
// optional .google.protobuf.FieldOptions options = 8; // optional .google.protobuf.FieldOptions options = 8;
bool has_options() const; bool has_options() const;
void clear_options(); void clear_options();
@ -1160,6 +1172,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
inline void clear_has_default_value(); inline void clear_has_default_value();
inline void set_has_oneof_index(); inline void set_has_oneof_index();
inline void clear_has_oneof_index(); inline void clear_has_oneof_index();
inline void set_has_json_name();
inline void clear_has_json_name();
inline void set_has_options(); inline void set_has_options();
inline void clear_has_options(); inline void clear_has_options();
@ -1174,6 +1188,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
int type_; int type_;
::google::protobuf::int32 oneof_index_; ::google::protobuf::int32 oneof_index_;
::google::protobuf::internal::ArenaStringPtr default_value_; ::google::protobuf::internal::ArenaStringPtr default_value_;
::google::protobuf::internal::ArenaStringPtr json_name_;
::google::protobuf::FieldOptions* options_; ::google::protobuf::FieldOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
@ -4678,15 +4693,68 @@ inline void FieldDescriptorProto::set_oneof_index(::google::protobuf::int32 valu
// @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index) // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
} }
// optional string json_name = 10;
inline bool FieldDescriptorProto::has_json_name() const {
return (_has_bits_[0] & 0x00000100u) != 0;
}
inline void FieldDescriptorProto::set_has_json_name() {
_has_bits_[0] |= 0x00000100u;
}
inline void FieldDescriptorProto::clear_has_json_name() {
_has_bits_[0] &= ~0x00000100u;
}
inline void FieldDescriptorProto::clear_json_name() {
json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
clear_has_json_name();
}
inline const ::std::string& FieldDescriptorProto::json_name() const {
// @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_json_name(const ::std::string& value) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
}
inline void FieldDescriptorProto::set_json_name(const char* value) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
}
inline void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
set_has_json_name();
json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
}
inline ::std::string* FieldDescriptorProto::mutable_json_name() {
set_has_json_name();
// @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* FieldDescriptorProto::release_json_name() {
clear_has_json_name();
return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
if (json_name != NULL) {
set_has_json_name();
} else {
clear_has_json_name();
}
json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
}
// optional .google.protobuf.FieldOptions options = 8; // optional .google.protobuf.FieldOptions options = 8;
inline bool FieldDescriptorProto::has_options() const { inline bool FieldDescriptorProto::has_options() const {
return (_has_bits_[0] & 0x00000100u) != 0; return (_has_bits_[0] & 0x00000200u) != 0;
} }
inline void FieldDescriptorProto::set_has_options() { inline void FieldDescriptorProto::set_has_options() {
_has_bits_[0] |= 0x00000100u; _has_bits_[0] |= 0x00000200u;
} }
inline void FieldDescriptorProto::clear_has_options() { inline void FieldDescriptorProto::clear_has_options() {
_has_bits_[0] &= ~0x00000100u; _has_bits_[0] &= ~0x00000200u;
} }
inline void FieldDescriptorProto::clear_options() { inline void FieldDescriptorProto::clear_options() {
if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();

@ -190,6 +190,12 @@ message FieldDescriptorProto {
// list. This field is a member of that oneof. // list. This field is a member of that oneof.
optional int32 oneof_index = 9; optional int32 oneof_index = 9;
// JSON name of this field. The value is set by protocol compiler. If the
// user has set a "json_name" option on this field, that option's value
// will be used. Otherwise, it's deduced from the field's name by converting
// it to camelCase.
optional string json_name = 10;
optional FieldOptions options = 8; optional FieldOptions options = 8;
} }

@ -35,6 +35,10 @@
// This file makes extensive use of RFC 3092. :) // This file makes extensive use of RFC 3092. :)
#include <algorithm> #include <algorithm>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/descriptor_database.h> #include <google/protobuf/descriptor_database.h>
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
@ -177,7 +181,7 @@ class DescriptorDatabaseTest
EXPECT_FALSE(test_case_->AddToDatabase(file_proto)); EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
} }
scoped_ptr<DescriptorDatabaseTestCase> test_case_; google::protobuf::scoped_ptr<DescriptorDatabaseTestCase> test_case_;
DescriptorDatabase* database_; DescriptorDatabase* database_;
}; };

@ -34,6 +34,10 @@
// //
// This file makes extensive use of RFC 3092. :) // This file makes extensive use of RFC 3092. :)
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <vector> #include <vector>
#include <google/protobuf/compiler/importer.h> #include <google/protobuf/compiler/importer.h>
@ -461,6 +465,16 @@ class DescriptorTest : public testing::Test {
// map<int32, int32> map_int32_int32 = 1; // map<int32, int32> map_int32_int32 = 1;
// } // }
// //
// // in "json.proto"
// message TestMessage4 {
// optional int32 field_name1 = 1;
// optional int32 fieldName2 = 2;
// optional int32 FieldName3 = 3;
// optional int32 _field_name4 = 4;
// optional int32 FIELD_NAME5 = 5;
// optional int32 field_name6 = 6 [json_name = "@type"];
// }
//
// We cheat and use TestForeign as the type for qux rather than create // We cheat and use TestForeign as the type for qux rather than create
// an actual nested type. // an actual nested type.
// //
@ -526,6 +540,30 @@ class DescriptorTest : public testing::Test {
FieldDescriptorProto::TYPE_MESSAGE) FieldDescriptorProto::TYPE_MESSAGE)
->set_type_name("MapInt32Int32Entry"); ->set_type_name("MapInt32Int32Entry");
FileDescriptorProto json_file;
json_file.set_name("json.proto");
json_file.set_syntax("proto3");
DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
AddField(message4, "field_name1", 1,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32);
AddField(message4, "fieldName2", 2,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32);
AddField(message4, "FieldName3", 3,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32);
AddField(message4, "_field_name4", 4,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32);
AddField(message4, "FIELD_NAME5", 5,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32);
AddField(message4, "field_name6", 6,
FieldDescriptorProto::LABEL_OPTIONAL,
FieldDescriptorProto::TYPE_INT32)
->set_json_name("@type");
// Build the descriptors and get the pointers. // Build the descriptors and get the pointers.
foo_file_ = pool_.BuildFile(foo_file); foo_file_ = pool_.BuildFile(foo_file);
ASSERT_TRUE(foo_file_ != NULL); ASSERT_TRUE(foo_file_ != NULL);
@ -536,6 +574,9 @@ class DescriptorTest : public testing::Test {
map_file_ = pool_.BuildFile(map_file); map_file_ = pool_.BuildFile(map_file);
ASSERT_TRUE(map_file_ != NULL); ASSERT_TRUE(map_file_ != NULL);
json_file_ = pool_.BuildFile(json_file);
ASSERT_TRUE(json_file_ != NULL);
ASSERT_EQ(1, foo_file_->enum_type_count()); ASSERT_EQ(1, foo_file_->enum_type_count());
enum_ = foo_file_->enum_type(0); enum_ = foo_file_->enum_type(0);
@ -562,6 +603,14 @@ class DescriptorTest : public testing::Test {
ASSERT_EQ(1, message3_->field_count()); ASSERT_EQ(1, message3_->field_count());
map_ = message3_->field(0); map_ = message3_->field(0);
ASSERT_EQ(1, json_file_->message_type_count());
message4_ = json_file_->message_type(0);
}
void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
message->CopyTo(proto);
message->CopyJsonNameTo(proto);
} }
DescriptorPool pool_; DescriptorPool pool_;
@ -569,10 +618,12 @@ class DescriptorTest : public testing::Test {
const FileDescriptor* foo_file_; const FileDescriptor* foo_file_;
const FileDescriptor* bar_file_; const FileDescriptor* bar_file_;
const FileDescriptor* map_file_; const FileDescriptor* map_file_;
const FileDescriptor* json_file_;
const Descriptor* message_; const Descriptor* message_;
const Descriptor* message2_; const Descriptor* message2_;
const Descriptor* message3_; const Descriptor* message3_;
const Descriptor* message4_;
const Descriptor* foreign_; const Descriptor* foreign_;
const EnumDescriptor* enum_; const EnumDescriptor* enum_;
@ -664,6 +715,35 @@ TEST_F(DescriptorTest, FieldFullName) {
EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name()); EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name());
} }
TEST_F(DescriptorTest, FieldJsonName) {
EXPECT_EQ("fieldName1", message4_->field(0)->json_name());
EXPECT_EQ("fieldName2", message4_->field(1)->json_name());
EXPECT_EQ("fieldName3", message4_->field(2)->json_name());
EXPECT_EQ("fieldName4", message4_->field(3)->json_name());
EXPECT_EQ("fIELDNAME5", message4_->field(4)->json_name());
EXPECT_EQ("@type", message4_->field(5)->json_name());
DescriptorProto proto;
message4_->CopyTo(&proto);
ASSERT_EQ(6, proto.field_size());
EXPECT_FALSE(proto.field(0).has_json_name());
EXPECT_FALSE(proto.field(1).has_json_name());
EXPECT_FALSE(proto.field(2).has_json_name());
EXPECT_FALSE(proto.field(3).has_json_name());
EXPECT_FALSE(proto.field(4).has_json_name());
EXPECT_EQ("@type", proto.field(5).json_name());
proto.Clear();
CopyWithJsonName(message4_, &proto);
ASSERT_EQ(6, proto.field_size());
EXPECT_EQ("fieldName1", proto.field(0).json_name());
EXPECT_EQ("fieldName2", proto.field(1).json_name());
EXPECT_EQ("fieldName3", proto.field(2).json_name());
EXPECT_EQ("fieldName4", proto.field(3).json_name());
EXPECT_EQ("fIELDNAME5", proto.field(4).json_name());
EXPECT_EQ("@type", proto.field(5).json_name());
}
TEST_F(DescriptorTest, FieldFile) { TEST_F(DescriptorTest, FieldFile) {
EXPECT_EQ(foo_file_, foo_->file()); EXPECT_EQ(foo_file_, foo_->file());
EXPECT_EQ(foo_file_, bar_->file()); EXPECT_EQ(foo_file_, bar_->file());
@ -1900,7 +1980,7 @@ class MiscTest : public testing::Test {
return field != NULL ? field->enum_type() : NULL; return field != NULL ? field->enum_type() : NULL;
} }
scoped_ptr<DescriptorPool> pool_; google::protobuf::scoped_ptr<DescriptorPool> pool_;
}; };
TEST_F(MiscTest, TypeNames) { TEST_F(MiscTest, TypeNames) {
@ -2330,7 +2410,7 @@ class AllowUnknownDependenciesTest
const FieldDescriptor* qux_field_; const FieldDescriptor* qux_field_;
SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode. SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
scoped_ptr<DescriptorPool> pool_; google::protobuf::scoped_ptr<DescriptorPool> pool_;
}; };
TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) { TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
@ -5681,6 +5761,32 @@ TEST_F(ValidationErrorTest, ValidateProto3Extension) {
"defining options.\n"); "defining options.\n");
} }
// Test that field names that may conflict in JSON is not allowed by protoc.
TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
// The comparison is case-insensitive.
BuildFileWithErrors(
"name: 'foo.proto' "
"syntax: 'proto3' "
"message_type {"
" name: 'Foo'"
" field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
" field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
"}",
"foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" "
"conflicts with field \"name\". This is not allowed in proto3.\n");
// Underscores are ignored.
BuildFileWithErrors(
"name: 'foo.proto' "
"syntax: 'proto3' "
"message_type {"
" name: 'Foo'"
" field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
" field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
"}",
"foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" "
"conflicts with field \"ab\". This is not allowed in proto3.\n");
}
// =================================================================== // ===================================================================
// DescriptorDatabase // DescriptorDatabase

@ -64,6 +64,10 @@
#include <algorithm> #include <algorithm>
#include <google/protobuf/stubs/hash.h> #include <google/protobuf/stubs/hash.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
@ -229,8 +233,8 @@ class DynamicMessage : public Message {
// Warning: The order in which the following pointers are defined is // Warning: The order in which the following pointers are defined is
// important (the prototype must be deleted *before* the offsets). // important (the prototype must be deleted *before* the offsets).
scoped_array<int> offsets; google::protobuf::scoped_array<int> offsets;
scoped_ptr<const GeneratedMessageReflection> reflection; google::protobuf::scoped_ptr<const GeneratedMessageReflection> reflection;
// Don't use a scoped_ptr to hold the prototype: the destructor for // Don't use a scoped_ptr to hold the prototype: the destructor for
// DynamicMessage needs to know whether it is the prototype, and does so by // DynamicMessage needs to know whether it is the prototype, and does so by
// looking back at this field. This would assume details about the // looking back at this field. This would assume details about the

@ -40,6 +40,11 @@
// reflection_ops_unittest, cover the rest of the functionality used by // reflection_ops_unittest, cover the rest of the functionality used by
// DynamicMessage. // DynamicMessage.
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
#include <google/protobuf/dynamic_message.h> #include <google/protobuf/dynamic_message.h>
@ -144,7 +149,7 @@ TEST_F(DynamicMessageTest, IndependentOffsets) {
// Check that all fields have independent offsets by setting each // Check that all fields have independent offsets by setting each
// one to a unique value then checking that they all still have those // one to a unique value then checking that they all still have those
// unique values (i.e. they don't stomp each other). // unique values (i.e. they don't stomp each other).
scoped_ptr<Message> message(prototype_->New()); google::protobuf::scoped_ptr<Message> message(prototype_->New());
TestUtil::ReflectionTester reflection_tester(descriptor_); TestUtil::ReflectionTester reflection_tester(descriptor_);
reflection_tester.SetAllFieldsViaReflection(message.get()); reflection_tester.SetAllFieldsViaReflection(message.get());
@ -153,7 +158,7 @@ TEST_F(DynamicMessageTest, IndependentOffsets) {
TEST_F(DynamicMessageTest, Extensions) { TEST_F(DynamicMessageTest, Extensions) {
// Check that extensions work. // Check that extensions work.
scoped_ptr<Message> message(extensions_prototype_->New()); google::protobuf::scoped_ptr<Message> message(extensions_prototype_->New());
TestUtil::ReflectionTester reflection_tester(extensions_descriptor_); TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
reflection_tester.SetAllFieldsViaReflection(message.get()); reflection_tester.SetAllFieldsViaReflection(message.get());
@ -162,7 +167,7 @@ TEST_F(DynamicMessageTest, Extensions) {
TEST_F(DynamicMessageTest, PackedFields) { TEST_F(DynamicMessageTest, PackedFields) {
// Check that packed fields work properly. // Check that packed fields work properly.
scoped_ptr<Message> message(packed_prototype_->New()); google::protobuf::scoped_ptr<Message> message(packed_prototype_->New());
TestUtil::ReflectionTester reflection_tester(packed_descriptor_); TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
reflection_tester.SetPackedFieldsViaReflection(message.get()); reflection_tester.SetPackedFieldsViaReflection(message.get());
@ -171,7 +176,7 @@ TEST_F(DynamicMessageTest, PackedFields) {
TEST_F(DynamicMessageTest, Oneof) { TEST_F(DynamicMessageTest, Oneof) {
// Check that oneof fields work properly. // Check that oneof fields work properly.
scoped_ptr<Message> message(oneof_prototype_->New()); google::protobuf::scoped_ptr<Message> message(oneof_prototype_->New());
// Check default values. // Check default values.
const Descriptor* descriptor = message->GetDescriptor(); const Descriptor* descriptor = message->GetDescriptor();
@ -232,7 +237,7 @@ TEST_F(DynamicMessageTest, SpaceUsed) {
// Since we share the implementation with generated messages, we don't need // Since we share the implementation with generated messages, we don't need
// to test very much here. Just make sure it appears to be working. // to test very much here. Just make sure it appears to be working.
scoped_ptr<Message> message(prototype_->New()); google::protobuf::scoped_ptr<Message> message(prototype_->New());
TestUtil::ReflectionTester reflection_tester(descriptor_); TestUtil::ReflectionTester reflection_tester(descriptor_);
int initial_space_used = message->SpaceUsed(); int initial_space_used = message->SpaceUsed();

@ -34,6 +34,7 @@
#include <google/protobuf/stubs/hash.h> #include <google/protobuf/stubs/hash.h>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/extension_set.h> #include <google/protobuf/extension_set.h>
#include <google/protobuf/message_lite.h> #include <google/protobuf/message_lite.h>
#include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/coded_stream.h>
@ -594,20 +595,21 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
ClearExtension(number); ClearExtension(number);
return; return;
} }
::google::protobuf::Arena* message_arena = message->GetArena();
Extension* extension; Extension* extension;
if (MaybeNewExtension(number, descriptor, &extension)) { if (MaybeNewExtension(number, descriptor, &extension)) {
extension->type = type; extension->type = type;
GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_lazy = false; extension->is_lazy = false;
if (message->GetArena() == arena_) { if (message_arena == arena_) {
extension->message_value = message; extension->message_value = message;
} else if (message_arena == NULL) {
extension->message_value = message;
arena_->Own(message); // not NULL because not equal to message_arena
} else { } else {
extension->message_value = message->New(arena_); extension->message_value = message->New(arena_);
extension->message_value->CheckTypeAndMergeFrom(*message); extension->message_value->CheckTypeAndMergeFrom(*message);
if (message->GetArena() == NULL) {
delete message;
}
} }
} else { } else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
@ -617,14 +619,14 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
if (arena_ == NULL) { if (arena_ == NULL) {
delete extension->message_value; delete extension->message_value;
} }
if (message->GetArena() == arena_) { if (message_arena == arena_) {
extension->message_value = message; extension->message_value = message;
} else if (message_arena == NULL) {
extension->message_value = message;
arena_->Own(message); // not NULL because not equal to message_arena
} else { } else {
extension->message_value = message->New(arena_); extension->message_value = message->New(arena_);
extension->message_value->CheckTypeAndMergeFrom(*message); extension->message_value->CheckTypeAndMergeFrom(*message);
if (message->GetArena() == NULL) {
delete message;
}
} }
} }
} }

@ -724,8 +724,7 @@ class RepeatedPrimitiveTypeTraits {
static const RepeatedFieldType* GetDefaultRepeatedField(); static const RepeatedFieldType* GetDefaultRepeatedField();
}; };
LIBPROTOBUF_EXPORT extern ProtobufOnceType LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_;
repeated_primitive_generic_type_traits_once_init_;
class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits { class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
private: private:
@ -766,7 +765,7 @@ template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
} \ } \
template<> inline const RepeatedField<TYPE>* \ template<> inline const RepeatedField<TYPE>* \
RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() { \ RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() { \
GoogleOnceInit( \ ::google::protobuf::GoogleOnceInit( \
&repeated_primitive_generic_type_traits_once_init_, \ &repeated_primitive_generic_type_traits_once_init_, \
&RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \ &RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \
return RepeatedPrimitiveGenericTypeTraits:: \ return RepeatedPrimitiveGenericTypeTraits:: \
@ -822,8 +821,7 @@ class LIBPROTOBUF_EXPORT StringTypeTraits {
} }
}; };
LIBPROTOBUF_EXPORT extern ProtobufOnceType LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_;
repeated_string_type_traits_once_init_;
class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
public: public:
@ -868,7 +866,7 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
} }
static const RepeatedFieldType* GetDefaultRepeatedField() { static const RepeatedFieldType* GetDefaultRepeatedField() {
GoogleOnceInit(&repeated_string_type_traits_once_init_, ::google::protobuf::GoogleOnceInit(&repeated_string_type_traits_once_init_,
&InitializeDefaultRepeatedFields); &InitializeDefaultRepeatedFields);
return default_repeated_field_; return default_repeated_field_;
} }
@ -1034,8 +1032,7 @@ class RepeatedMessageTypeTraits {
static const RepeatedFieldType* GetDefaultRepeatedField(); static const RepeatedFieldType* GetDefaultRepeatedField();
}; };
LIBPROTOBUF_EXPORT extern ProtobufOnceType LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_once_init_;
repeated_message_generic_type_traits_once_init_;
// This class exists only to hold a generic default empty repeated field for all // This class exists only to hold a generic default empty repeated field for all
// message-type repeated field extensions. // message-type repeated field extensions.
@ -1052,7 +1049,7 @@ class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits {
template<typename Type> inline template<typename Type> inline
const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType* const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() { RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
GoogleOnceInit( ::google::protobuf::GoogleOnceInit(
&repeated_message_generic_type_traits_once_init_, &repeated_message_generic_type_traits_once_init_,
&RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields); &RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields);
return reinterpret_cast<const RepeatedFieldType*>( return reinterpret_cast<const RepeatedFieldType*>(

@ -360,9 +360,8 @@ TEST(ExtensionSetTest, ArenaSetAllocatedMessageAndRelease) {
unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage(); unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
message->SetAllocatedExtension(unittest::optional_foreign_message_extension, message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
foreign_message); foreign_message);
// foreign_message is copied underneath, as foreign_message is on heap // foreign_message is now owned by the arena.
// and extension_set is on an arena. EXPECT_EQ(foreign_message,
EXPECT_NE(foreign_message,
message->MutableExtension( message->MutableExtension(
unittest::optional_foreign_message_extension)); unittest::optional_foreign_message_extension));

@ -43,6 +43,11 @@
// rather than generated accessors. // rather than generated accessors.
#include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/generated_message_reflection.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/test_util.h> #include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest.pb.h>
@ -354,7 +359,7 @@ TEST(GeneratedMessageReflectionTest, ReleaseLast) {
ASSERT_EQ(2, message.repeated_foreign_message_size()); ASSERT_EQ(2, message.repeated_foreign_message_size());
const protobuf_unittest::ForeignMessage* expected = const protobuf_unittest::ForeignMessage* expected =
message.mutable_repeated_foreign_message(1); message.mutable_repeated_foreign_message(1);
scoped_ptr<Message> released(message.GetReflection()->ReleaseLast( google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
&message, descriptor->FindFieldByName("repeated_foreign_message"))); &message, descriptor->FindFieldByName("repeated_foreign_message")));
EXPECT_EQ(expected, released.get()); EXPECT_EQ(expected, released.get());
} }
@ -377,9 +382,9 @@ TEST(GeneratedMessageReflectionTest, ReleaseLastExtensions) {
unittest::repeated_foreign_message_extension)); unittest::repeated_foreign_message_extension));
const protobuf_unittest::ForeignMessage* expected = message.MutableExtension( const protobuf_unittest::ForeignMessage* expected = message.MutableExtension(
unittest::repeated_foreign_message_extension, 1); unittest::repeated_foreign_message_extension, 1);
scoped_ptr<Message> released(message.GetReflection()->ReleaseLast( google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
&message, descriptor->file()->FindExtensionByName( &message, descriptor->file()->FindExtensionByName(
"repeated_foreign_message_extension"))); "repeated_foreign_message_extension")));
EXPECT_EQ(expected, released.get()); EXPECT_EQ(expected, released.get());
} }

@ -63,7 +63,6 @@ void InitEmptyString() {
int StringSpaceUsedExcludingSelf(const string& str) { int StringSpaceUsedExcludingSelf(const string& str) {
const void* start = &str; const void* start = &str;
const void* end = &str + 1; const void* end = &str + 1;
if (start <= str.data() && str.data() < end) { if (start <= str.data() && str.data() < end) {
// The string's data is stored inside the string object itself. // The string's data is stored inside the string object itself.
return 0; return 0;
@ -73,6 +72,7 @@ int StringSpaceUsedExcludingSelf(const string& str) {
} }
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

@ -34,6 +34,10 @@
// //
// This file contains tests and benchmarks. // This file contains tests and benchmarks.
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <vector> #include <vector>
#include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/coded_stream.h>
@ -679,7 +683,7 @@ TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) {
} }
TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) { TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
scoped_array<uint8> buffer(new uint8[8]); google::protobuf::scoped_array<uint8> buffer(new uint8[8]);
CodedInputStream coded_input(buffer.get(), 8); CodedInputStream coded_input(buffer.get(), 8);
string str; string str;
EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));

@ -44,6 +44,10 @@
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string> #include <string>
#include <iosfwd> #include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream.h>
@ -235,7 +239,7 @@ class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream
// Data is read into this buffer. It may be NULL if no buffer is currently // Data is read into this buffer. It may be NULL if no buffer is currently
// in use. Otherwise, it points to an array of size buffer_size_. // in use. Otherwise, it points to an array of size buffer_size_.
scoped_array<uint8> buffer_; google::protobuf::scoped_array<uint8> buffer_;
const int buffer_size_; const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last // Number of valid bytes currently in the buffer (i.e. the size last
@ -324,7 +328,7 @@ class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStrea
// Data is written from this buffer. It may be NULL if no buffer is // Data is written from this buffer. It may be NULL if no buffer is
// currently in use. Otherwise, it points to an array of size buffer_size_. // currently in use. Otherwise, it points to an array of size buffer_size_.
scoped_array<uint8> buffer_; google::protobuf::scoped_array<uint8> buffer_;
const int buffer_size_; const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last // Number of valid bytes currently in the buffer (i.e. the size last

@ -57,6 +57,10 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <sstream> #include <sstream>
#include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/zero_copy_stream_impl.h>
@ -197,7 +201,7 @@ void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
} }
void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) { void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
scoped_array<char> buffer(new char[str.size() + 1]); google::protobuf::scoped_array<char> buffer(new char[str.size() + 1]);
buffer[str.size()] = '\0'; buffer[str.size()] = '\0';
EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size()); EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
EXPECT_STREQ(str.c_str(), buffer.get()); EXPECT_STREQ(str.c_str(), buffer.get());

@ -155,7 +155,8 @@ void TypeDefinedMapFieldBase<Key, T>::CopyIterator(
this_iter->key_.SetType(that_iter.key_.type()); this_iter->key_.SetType(that_iter.key_.type());
// MapValueRef::type() fails when containing data is null. However, if // MapValueRef::type() fails when containing data is null. However, if
// this_iter points to MapEnd, data can be null. // this_iter points to MapEnd, data can be null.
this_iter->value_.SetType((FieldDescriptor::CppType)that_iter.value_.type_); this_iter->value_.SetType(
static_cast<FieldDescriptor::CppType>(that_iter.value_.type_));
SetMapIteratorValue(this_iter); SetMapIteratorValue(this_iter);
} }

@ -31,6 +31,8 @@
syntax = "proto2"; syntax = "proto2";
import "google/protobuf/unittest_import.proto";
// We don't put this in a package within proto2 because we need to make sure // We don't put this in a package within proto2 because we need to make sure
// that the generated code doesn't depend on being in the proto2 namespace. // that the generated code doesn't depend on being in the proto2 namespace.
// In map_test_util.h we do "using namespace unittest = protobuf_unittest". // In map_test_util.h we do "using namespace unittest = protobuf_unittest".
@ -58,3 +60,7 @@ message TestEnumMapPlusExtra {
map<int32, Proto2MapEnumPlusExtra> known_map_field = 101; map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102; map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
} }
message TestImportEnumMap {
map<int32, protobuf_unittest_import.ImportEnumForMap> import_enum_amp = 1;
}

@ -2154,7 +2154,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
// Check that all fields have independent offsets by setting each // Check that all fields have independent offsets by setting each
// one to a unique value then checking that they all still have those // one to a unique value then checking that they all still have those
// unique values (i.e. they don't stomp each other). // unique values (i.e. they don't stomp each other).
scoped_ptr<Message> message(map_prototype_->New()); google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
MapReflectionTester reflection_tester(map_descriptor_); MapReflectionTester reflection_tester(map_descriptor_);
reflection_tester.SetMapFieldsViaReflection(message.get()); reflection_tester.SetMapFieldsViaReflection(message.get());
@ -2163,7 +2163,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) { TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
// Check that map fields work properly. // Check that map fields work properly.
scoped_ptr<Message> message(map_prototype_->New()); google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
// Check set functions. // Check set functions.
MapReflectionTester reflection_tester(map_descriptor_); MapReflectionTester reflection_tester(map_descriptor_);
@ -2177,7 +2177,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
// Since we share the implementation with generated messages, we don't need // Since we share the implementation with generated messages, we don't need
// to test very much here. Just make sure it appears to be working. // to test very much here. Just make sure it appears to be working.
scoped_ptr<Message> message(map_prototype_->New()); google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
MapReflectionTester reflection_tester(map_descriptor_); MapReflectionTester reflection_tester(map_descriptor_);
int initial_space_used = message->SpaceUsed(); int initial_space_used = message->SpaceUsed();

@ -55,7 +55,6 @@
#include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/singleton.h> #include <google/protobuf/stubs/singleton.h>
#include <google/protobuf/stubs/stl_util.h> #include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/port.h>
namespace google { namespace google {
namespace protobuf { namespace protobuf {

@ -971,7 +971,7 @@ class LIBPROTOBUF_EXPORT Reflection {
return false; return false;
} }
// Returns a MaIterator referring to the first element in the map field. // Returns a MapIterator referring to the first element in the map field.
// If the map field is empty, this function returns the same as // If the map field is empty, this function returns the same as
// reflection::MapEnd. Mutation to the field may invalidate the iterator. // reflection::MapEnd. Mutation to the field may invalidate the iterator.
virtual MapIterator MapBegin( virtual MapIterator MapBegin(

@ -649,7 +649,7 @@ inline const Message& GenericTypeHandler<Message>::default_instance() {
// StringTypeHandler is exported. So, we factor out StringTypeHandlerBase, // StringTypeHandler is exported. So, we factor out StringTypeHandlerBase,
// export that, then make StringTypeHandler be a subclass which is NOT // export that, then make StringTypeHandler be a subclass which is NOT
// exported. // exported.
// TODO(kenton): Now that StringSpaceUsedExcludingSelf() is in the lite // TODO(kenton): Now that StringSpaceUsedExcludingSelf() is in the lite
// library, this can be cleaned up. // library, this can be cleaned up.
class LIBPROTOBUF_EXPORT StringTypeHandlerBase { class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
public: public:

@ -149,6 +149,7 @@
#include <string> #include <string>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/hash.h>
namespace google { namespace google {
namespace protobuf { namespace protobuf {
@ -437,4 +438,16 @@ extern std::ostream& operator<<(std::ostream& o, StringPiece piece);
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
template<> struct hash<StringPiece> {
size_t operator()(const StringPiece& s) const {
size_t result = 0;
for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {
result = 5 * result + *str;
}
return result;
}
};
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
#endif // STRINGS_STRINGPIECE_H_ #endif // STRINGS_STRINGPIECE_H_

@ -36,6 +36,7 @@
#include <vector> #include <vector>
#include <google/protobuf/testing/googletest.h> #include <google/protobuf/testing/googletest.h>
#include <google/protobuf/stubs/hash.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace google { namespace google {
@ -745,6 +746,23 @@ TEST(StringPiece, Comparisons2) {
EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz")); EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz"));
} }
TEST(StringPiece, HashFunction) {
hash_set<StringPiece> set;
set.insert(StringPiece("hello"));
EXPECT_EQ(1, set.size());
// Insert a StringPiece of the same value again and should NOT increment
// size of the set.
set.insert(StringPiece("hello"));
EXPECT_EQ(1, set.size());
// Insert a StringPiece with different value and check that size of the set
// has been increment by one.
set.insert(StringPiece("world"));
EXPECT_EQ(2, set.size());
}
TEST(ComparisonOpsTest, StringCompareNotAmbiguous) { TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
EXPECT_EQ("hello", string("hello")); EXPECT_EQ("hello", string("hello"));
EXPECT_LT("hello", string("world")); EXPECT_LT("hello", string("world"));

@ -377,8 +377,8 @@ class TextFormat::Parser::ParserImpl {
if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field, if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field,
&any_value_field) && &any_value_field) &&
TryConsume("[")) { TryConsume("[")) {
string full_type_name; string full_type_name, prefix;
DO(ConsumeAnyTypeUrl(&full_type_name)); DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
DO(Consume("]")); DO(Consume("]"));
string serialized_value; string serialized_value;
DO(ConsumeAnyValue(full_type_name, DO(ConsumeAnyValue(full_type_name,
@ -386,7 +386,7 @@ class TextFormat::Parser::ParserImpl {
&serialized_value)); &serialized_value));
reflection->SetString( reflection->SetString(
message, any_type_url_field, message, any_type_url_field,
string(internal::kTypeGoogleApisComPrefix) + full_type_name); string(prefix + full_type_name));
reflection->SetString(message, any_value_field, serialized_value); reflection->SetString(message, any_value_field, serialized_value);
return true; return true;
// Fall through. // Fall through.
@ -981,7 +981,8 @@ class TextFormat::Parser::ParserImpl {
} }
// Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name" // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
bool ConsumeAnyTypeUrl(string* full_type_name) { // or "type.googleprod.com/full.type.Name"
bool ConsumeAnyTypeUrl(string* full_type_name, string* prefix) {
// TODO(saito) Extend Consume() to consume multiple tokens at once, so that // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
// this code can be written as just DO(Consume(kGoogleApisTypePrefix)). // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
string url1, url2, url3; string url1, url2, url3;
@ -993,10 +994,12 @@ class TextFormat::Parser::ParserImpl {
DO(Consume("/")); DO(Consume("/"));
DO(ConsumeFullTypeName(full_type_name)); DO(ConsumeFullTypeName(full_type_name));
const string prefix = url1 + "." + url2 + "." + url3 + "/"; *prefix = url1 + "." + url2 + "." + url3 + "/";
if (prefix != internal::kTypeGoogleApisComPrefix) { if (*prefix != internal::kTypeGoogleApisComPrefix &&
*prefix != internal::kTypeGoogleProdComPrefix) {
ReportError("TextFormat::Parser for Any supports only " ReportError("TextFormat::Parser for Any supports only "
"type.googleapi.com, but found \"" + prefix + "\""); "type.googleapis.com and type.googleprod.com, "
"but found \"" + *prefix + "\"");
return false; return false;
} }
return true; return true;

@ -37,6 +37,10 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits> #include <limits>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
@ -931,7 +935,7 @@ class TextFormatParserTest : public testing::Test {
protected: protected:
void ExpectFailure(const string& input, const string& message, int line, void ExpectFailure(const string& input, const string& message, int line,
int col) { int col) {
scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes); google::protobuf::scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
ExpectFailure(input, message, line, col, proto.get()); ExpectFailure(input, message, line, col, proto.get());
} }
@ -992,7 +996,7 @@ class TextFormatParserTest : public testing::Test {
}; };
TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) { TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes); google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
const Descriptor* d = message->GetDescriptor(); const Descriptor* d = message->GetDescriptor();
string stringData = string stringData =
@ -1057,7 +1061,7 @@ TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
} }
TEST_F(TextFormatParserTest, ParseFieldValueFromString) { TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes); google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
const Descriptor* d = message->GetDescriptor(); const Descriptor* d = message->GetDescriptor();
#define EXPECT_FIELD(name, value, valuestring) \ #define EXPECT_FIELD(name, value, valuestring) \

@ -64,3 +64,10 @@ enum ImportEnum {
IMPORT_BAZ = 9; IMPORT_BAZ = 9;
} }
// To use an enum in a map, it must has the first value as 0.
enum ImportEnumForMap {
UNKNOWN = 0;
FOO = 1;
BAR = 2;
}

@ -34,8 +34,8 @@
#include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest.pb.h>
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/mathutil.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <google/protobuf/stubs/mathutil.h>
namespace google { namespace google {
namespace protobuf { namespace protobuf {

@ -43,7 +43,7 @@ string FieldMaskUtil::ToString(const FieldMask& mask) {
return Join(mask.paths(), ","); return Join(mask.paths(), ",");
} }
void FieldMaskUtil::FromString(const string& str, FieldMask* out) { void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
out->Clear(); out->Clear();
vector<string> paths = Split(str, ","); vector<string> paths = Split(str, ",");
for (int i = 0; i < paths.size(); ++i) { for (int i = 0; i < paths.size(); ++i) {
@ -53,7 +53,7 @@ void FieldMaskUtil::FromString(const string& str, FieldMask* out) {
} }
bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
const string& path) { StringPiece path) {
vector<string> parts = Split(path, "."); vector<string> parts = Split(path, ".");
for (int i = 0; i < parts.size(); ++i) { for (int i = 0; i < parts.size(); ++i) {
const string& field_name = parts[i]; const string& field_name = parts[i];
@ -386,15 +386,15 @@ void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
intersection.MergeToFieldMask(out); intersection.MergeToFieldMask(out);
} }
bool FieldMaskUtil::IsPathInFieldMask(const string& path, bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
const FieldMask& mask) {
for (int i = 0; i < mask.paths_size(); ++i) { for (int i = 0; i < mask.paths_size(); ++i) {
const string& mask_path = mask.paths(i); const string& mask_path = mask.paths(i);
if (path == mask_path) { if (path == mask_path) {
return true; return true;
} else if (mask_path.length() < path.length()) { } else if (mask_path.length() < path.length()) {
// Also check whether mask.paths(i) is a prefix of path. // Also check whether mask.paths(i) is a prefix of path.
if (path.compare(0, mask_path.length() + 1, mask_path + ".") == 0) { if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
0) {
return true; return true;
} }
} }

@ -35,6 +35,7 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/field_mask.pb.h> #include <google/protobuf/field_mask.pb.h>
#include <google/protobuf/stubs/stringpiece.h>
namespace google { namespace google {
namespace protobuf { namespace protobuf {
@ -47,11 +48,11 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
// Converts FieldMask to/from string, formatted according to proto3 JSON // Converts FieldMask to/from string, formatted according to proto3 JSON
// spec for FieldMask (e.g., "foo,bar,baz.quz"). // spec for FieldMask (e.g., "foo,bar,baz.quz").
static string ToString(const FieldMask& mask); static string ToString(const FieldMask& mask);
static void FromString(const string& str, FieldMask* out); static void FromString(StringPiece str, FieldMask* out);
// Checks whether the given path is valid for type T. // Checks whether the given path is valid for type T.
template <typename T> template <typename T>
static bool IsValidPath(const string& path) { static bool IsValidPath(StringPiece path) {
return InternalIsValidPath(T::descriptor(), path); return InternalIsValidPath(T::descriptor(), path);
} }
@ -67,7 +68,7 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
// Adds a path to FieldMask after checking whether the given path is valid. // Adds a path to FieldMask after checking whether the given path is valid.
// This method check-fails if the path is not a valid path for type T. // This method check-fails if the path is not a valid path for type T.
template <typename T> template <typename T>
static void AddPathToFieldMask(const string& path, FieldMask* mask) { static void AddPathToFieldMask(StringPiece path, FieldMask* mask) {
GOOGLE_CHECK(IsValidPath<T>(path)); GOOGLE_CHECK(IsValidPath<T>(path));
mask->add_paths(path); mask->add_paths(path);
} }
@ -96,7 +97,7 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
// Returns true if path is covered by the given FieldMask. Note that path // Returns true if path is covered by the given FieldMask. Note that path
// "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc. // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc.
static bool IsPathInFieldMask(const string& path, const FieldMask& mask); static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
class MergeOptions; class MergeOptions;
// Merges fields specified in a FieldMask into another message. // Merges fields specified in a FieldMask into another message.
@ -105,7 +106,7 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
private: private:
static bool InternalIsValidPath(const Descriptor* descriptor, static bool InternalIsValidPath(const Descriptor* descriptor,
const string& path); StringPiece path);
static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor, static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor,
FieldMask* out); FieldMask* out);

@ -110,7 +110,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
// "Node" represents a node in the tree that holds the input of // "Node" represents a node in the tree that holds the input of
// DefaultValueObjectWriter. // DefaultValueObjectWriter.
class Node { class LIBPROTOBUF_EXPORT Node {
public: public:
Node(const string& name, const google::protobuf::Type* type, NodeKind kind, Node(const string& name, const google::protobuf::Type* type, NodeKind kind,
const DataPiece& data, bool is_placeholder); const DataPiece& data, bool is_placeholder);

@ -37,8 +37,8 @@
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/util/internal/json_escaping.h> #include <google/protobuf/util/internal/json_escaping.h>
#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/mathlimits.h>
namespace google { namespace google {
namespace protobuf { namespace protobuf {
@ -116,7 +116,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
double value) { double value) {
if (google::protobuf::MathLimits<double>::IsFinite(value)) { if (MathLimits<double>::IsFinite(value)) {
return RenderSimple(name, SimpleDtoa(value)); return RenderSimple(name, SimpleDtoa(value));
} }
@ -126,7 +126,7 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name,
float value) { float value) {
if (google::protobuf::MathLimits<float>::IsFinite(value)) { if (MathLimits<float>::IsFinite(value)) {
return RenderSimple(name, SimpleFtoa(value)); return RenderSimple(name, SimpleFtoa(value));
} }

@ -47,7 +47,6 @@
#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/status_macros.h> #include <google/protobuf/stubs/status_macros.h>
@ -140,6 +139,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
const uint32 end_tag, const uint32 end_tag,
bool include_start_and_end, bool include_start_and_end,
ObjectWriter* ow) const { ObjectWriter* ow) const {
const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
if (type_renderer != NULL) { if (type_renderer != NULL) {
return (*type_renderer)(this, type, name, ow); return (*type_renderer)(this, type, name, ow);
@ -332,10 +332,9 @@ Status ProtoStreamObjectSource::RenderDuration(
if (seconds < 0) { if (seconds < 0) {
if (nanos > 0) { if (nanos > 0) {
return Status(util::error::INTERNAL, return Status(util::error::INTERNAL,
StrCat( StrCat("Duration nanos is non-negative, but seconds is "
"Duration nanos is non-negative, but seconds is " "negative for field: ",
"negative for field: ", field_name));
field_name));
} }
sign = "-"; sign = "-";
seconds = -seconds; seconds = -seconds;
@ -648,6 +647,7 @@ Status ProtoStreamObjectSource::RenderFieldMask(
return Status::OK; return Status::OK;
} }
hash_map<string, ProtoStreamObjectSource::TypeRenderer>* hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
ProtoStreamObjectSource::renderers_ = NULL; ProtoStreamObjectSource::renderers_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_); GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
@ -670,13 +670,16 @@ void ProtoStreamObjectSource::InitRendererMap() {
&ProtoStreamObjectSource::RenderInt32; &ProtoStreamObjectSource::RenderInt32;
(*renderers_)["google.protobuf.UInt32Value"] = (*renderers_)["google.protobuf.UInt32Value"] =
&ProtoStreamObjectSource::RenderUInt32; &ProtoStreamObjectSource::RenderUInt32;
(*renderers_)["google.protobuf.BoolValue"] = &ProtoStreamObjectSource::RenderBool; (*renderers_)["google.protobuf.BoolValue"] =
&ProtoStreamObjectSource::RenderBool;
(*renderers_)["google.protobuf.StringValue"] = (*renderers_)["google.protobuf.StringValue"] =
&ProtoStreamObjectSource::RenderString; &ProtoStreamObjectSource::RenderString;
(*renderers_)["google.protobuf.BytesValue"] = (*renderers_)["google.protobuf.BytesValue"] =
&ProtoStreamObjectSource::RenderBytes; &ProtoStreamObjectSource::RenderBytes;
(*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny; (*renderers_)["google.protobuf.Any"] =
(*renderers_)["google.protobuf.Struct"] = &ProtoStreamObjectSource::RenderStruct; &ProtoStreamObjectSource::RenderAny;
(*renderers_)["google.protobuf.Struct"] =
&ProtoStreamObjectSource::RenderStruct;
(*renderers_)["google.protobuf.Value"] = (*renderers_)["google.protobuf.Value"] =
&ProtoStreamObjectSource::RenderStructValue; &ProtoStreamObjectSource::RenderStructValue;
(*renderers_)["google.protobuf.ListValue"] = (*renderers_)["google.protobuf.ListValue"] =
@ -835,6 +838,7 @@ Status ProtoStreamObjectSource::RenderField(
StrCat("Invalid configuration. Could not find the type: ", StrCat("Invalid configuration. Could not find the type: ",
field->type_url())); field->type_url()));
} }
RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
if (!stream_->ConsumedEntireMessage()) { if (!stream_->ConsumedEntireMessage()) {
return Status(util::error::INVALID_ARGUMENT, return Status(util::error::INVALID_ARGUMENT,
@ -988,7 +992,7 @@ std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
uint32 nanos = 0; uint32 nanos = 0;
uint32 tag = 0; uint32 tag = 0;
int64 signed_seconds = 0; int64 signed_seconds = 0;
int64 signed_nanos = 0; int32 signed_nanos = 0;
for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
const google::protobuf::Field* field = FindAndVerifyField(type, tag); const google::protobuf::Field* field = FindAndVerifyField(type, tag);

@ -188,8 +188,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
// Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter. // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
static util::Status RenderStructListValue( static util::Status RenderStructListValue(
const ProtoStreamObjectSource* os, const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
const google::protobuf::Type& type,
StringPiece name, ObjectWriter* ow); StringPiece name, ObjectWriter* ow);
// Render the "Any" type. // Render the "Any" type.
@ -211,6 +210,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
util::Status RenderField(const google::protobuf::Field* field, util::Status RenderField(const google::protobuf::Field* field,
StringPiece field_name, ObjectWriter* ow) const; StringPiece field_name, ObjectWriter* ow) const;
// Reads field value according to Field spec in 'field' and returns the read // Reads field value according to Field spec in 'field' and returns the read
// value as string. This only works for primitive datatypes (no message // value as string. This only works for primitive datatypes (no message
// types). // types).

@ -33,13 +33,13 @@
#include <functional> #include <functional>
#include <stack> #include <stack>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/time.h> #include <google/protobuf/stubs/time.h>
#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/util/internal/field_mask_utility.h> #include <google/protobuf/util/internal/field_mask_utility.h>
#include <google/protobuf/util/internal/object_location_tracker.h> #include <google/protobuf/util/internal/object_location_tracker.h>
#include <google/protobuf/util/internal/constants.h> #include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/statusor.h> #include <google/protobuf/stubs/statusor.h>
@ -397,8 +397,8 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
const TypeRenderer* type_renderer = const TypeRenderer* type_renderer =
FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name())); FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name()));
if (type_renderer) { if (type_renderer) {
// TODO(rikka): Don't just ignore the util::Status object! Status status = (*type_renderer)(ow_.get(), value);
(*type_renderer)(ow_.get(), value); if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
} else { } else {
ow_->RenderDataPiece(name, value); ow_->RenderDataPiece(name, value);
} }
@ -600,6 +600,11 @@ void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) {
InsertIfNotPresent(&oneof_indices_, index); InsertIfNotPresent(&oneof_indices_, index);
} }
bool ProtoStreamObjectWriter::ProtoElement::InsertMapKeyIfNotPresent(
StringPiece map_key) {
return InsertIfNotPresent(&map_keys_, map_key);
}
inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name, inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name,
StringPiece message) { StringPiece message) {
listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
@ -643,6 +648,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
return this; return this;
} else if (element_ != NULL && } else if (element_ != NULL &&
(element_->IsMap() || element_->IsStructMap())) { (element_->IsMap() || element_->IsStructMap())) {
if (!ValidMapKey(name)) {
++invalid_depth_;
return this;
}
field = StartMapEntry(name); field = StartMapEntry(name);
if (element_->IsStructMapEntry()) { if (element_->IsStructMapEntry()) {
// If the top element is a map entry, this means we are starting another // If the top element is a map entry, this means we are starting another
@ -698,7 +708,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
element_.reset( element_.reset(
new ProtoElement(element_.release(), field, *type, ProtoElement::MAP)); new ProtoElement(element_.release(), field, *type, ProtoElement::MAP));
} else { } else {
WriteTag(*field); WriteTag(*field);
element_.reset(new ProtoElement(element_.release(), field, *type, element_.reset(new ProtoElement(element_.release(), field, *type,
ProtoElement::MESSAGE)); ProtoElement::MESSAGE));
} }
@ -863,6 +873,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
// struct. // struct.
SkipElements(); SkipElements();
// If ending the root element, // If ending the root element,
// then serialize the full message with calculated sizes. // then serialize the full message with calculated sizes.
if (element_ == NULL) { if (element_ == NULL) {
@ -914,6 +925,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
// Check if we need to start a map. This can heppen when there is either a map // Check if we need to start a map. This can heppen when there is either a map
// or a struct type within a list. // or a struct type within a list.
if (element_->IsMap() || element_->IsStructMap()) { if (element_->IsMap() || element_->IsStructMap()) {
if (!ValidMapKey(name)) {
++invalid_depth_;
return this;
}
field = StartMapEntry(name); field = StartMapEntry(name);
if (field == NULL) return this; if (field == NULL) return this;
@ -969,7 +985,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
ProtoElement::MESSAGE)); ProtoElement::MESSAGE));
InvalidValue("Map", "Cannot bind a list to map."); InvalidValue("Map", "Cannot bind a list to map.");
++invalid_depth_; ++invalid_depth_;
element_->pop(); element_.reset(element_->pop());
return this; return this;
} }
@ -1188,6 +1204,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
type_url = GetFullTypeWithUrl(master_type_.name()); type_url = GetFullTypeWithUrl(master_type_.name());
} else { } else {
if (element_->IsMap() || element_->IsStructMap()) { if (element_->IsMap() || element_->IsStructMap()) {
if (!ValidMapKey(name)) return this;
is_map_entry = true; is_map_entry = true;
field = StartMapEntry(name); field = StartMapEntry(name);
} else { } else {
@ -1462,6 +1479,19 @@ bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field,
return true; return true;
} }
bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
if (element_ == NULL) return true;
if (!element_->InsertMapKeyIfNotPresent(unnormalized_name)) {
InvalidName(
unnormalized_name,
StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
return false;
}
return true;
}
const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed( const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed(
StringPiece name, bool is_list) { StringPiece name, bool is_list) {
if (invalid_depth_ > 0) { if (invalid_depth_ > 0) {
@ -1614,6 +1644,7 @@ void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) {
stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
} }
} // namespace converter } // namespace converter
} // namespace util } // namespace util
} // namespace protobuf } // namespace protobuf

@ -259,6 +259,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// generate an error. // generate an error.
void TakeOneofIndex(int32 index); void TakeOneofIndex(int32 index);
// Inserts map key into hash set if and only if the key did NOT already
// exist in hash set.
// The hash set (map_keys_) is ONLY used to keep track of map keys.
// Return true if insert successfully; returns false if the map key was
// already present.
bool InsertMapKeyIfNotPresent(StringPiece map_key);
private: private:
// Used for access to variables of the enclosing instance of // Used for access to variables of the enclosing instance of
// ProtoStreamObjectWriter. // ProtoStreamObjectWriter.
@ -296,6 +303,10 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// incoming messages so no more than one oneof is set. // incoming messages so no more than one oneof is set.
hash_set<int32> oneof_indices_; hash_set<int32> oneof_indices_;
// Set of map keys already seen for the type_. Used to validate incoming
// messages so no map key appears more than once.
hash_set<StringPiece> map_keys_;
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
}; };
@ -378,6 +389,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// Helper method to write proto tags based on the given field. // Helper method to write proto tags based on the given field.
void WriteTag(const google::protobuf::Field& field); void WriteTag(const google::protobuf::Field& field);
// Helper function to render primitive data types in DataPiece. // Helper function to render primitive data types in DataPiece.
void RenderSimpleDataPiece(const google::protobuf::Field& field, void RenderSimpleDataPiece(const google::protobuf::Field& field,
const google::protobuf::Type& type, const google::protobuf::Type& type,
@ -424,6 +436,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
bool ValidOneof(const google::protobuf::Field& field, bool ValidOneof(const google::protobuf::Field& field,
StringPiece unnormalized_name); StringPiece unnormalized_name);
// Returns true if the map key for type_ is not duplicated key.
// If map key is duplicated key, this function returns false.
// Note that caller should make sure that the current proto element (element_)
// is of element type MAP or STRUCT_MAP.
// It also calls the appropriate error callback and unnormalzied_name is used
// for error string.
bool ValidMapKey(StringPiece unnormalized_name);
// Variables for describing the structure of the input tree: // Variables for describing the structure of the input tree:
// master_type_: descriptor for the whole protobuf message. // master_type_: descriptor for the whole protobuf message.
// typeinfo_ : the TypeInfo object to lookup types. // typeinfo_ : the TypeInfo object to lookup types.

@ -45,6 +45,7 @@
#include <google/protobuf/util/internal/testdata/field_mask.pb.h> #include <google/protobuf/util/internal/testdata/field_mask.pb.h>
#include <google/protobuf/util/internal/type_info_test_helper.h> #include <google/protobuf/util/internal/type_info_test_helper.h>
#include <google/protobuf/util/internal/constants.h> #include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/message_differencer.h>
#include <google/protobuf/stubs/bytestream.h> #include <google/protobuf/stubs/bytestream.h>
#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/util/internal/testdata/anys.pb.h> #include <google/protobuf/util/internal/testdata/anys.pb.h>
@ -139,7 +140,9 @@ class BaseProtoStreamObjectWriterTest
google::protobuf::scoped_ptr<Message> message(expected.New()); google::protobuf::scoped_ptr<Message> message(expected.New());
message->ParsePartialFromIstream(&istream); message->ParsePartialFromIstream(&istream);
EXPECT_EQ(expected.DebugString(), message->DebugString()); if (!MessageDifferencer::Equivalent(expected, *message)) {
EXPECT_EQ(expected.DebugString(), message->DebugString());
}
} }
void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } void CheckOutput(const Message& expected) { CheckOutput(expected, -1); }
@ -851,15 +854,19 @@ class ProtoStreamObjectWriterTimestampDurationTest
} }
}; };
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
ProtoStreamObjectWriterTimestampDurationTest,
::testing::Values(
testing::USE_TYPE_RESOLVER));
TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) {
TimestampDuration timestamp; TimestampDuration timestamp;
EXPECT_CALL( EXPECT_CALL(
listener_, listener_,
InvalidValue( InvalidValue(_,
_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
StringPiece("Field 'ts', Illegal timestamp format; timestamps " StringPiece("Field 'ts', Invalid time format: ")));
"must end with 'Z'")));
ow_->StartObject("")->RenderString("ts", "")->EndObject(); ow_->StartObject("")->RenderString("ts", "")->EndObject();
CheckOutput(timestamp); CheckOutput(timestamp);
@ -870,10 +877,9 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) {
EXPECT_CALL( EXPECT_CALL(
listener_, listener_,
InvalidValue( InvalidValue(_,
_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
StringPiece( StringPiece("Field 'ts', Invalid time format: Z")));
"Field 'ts', Invalid time format: Failed to parse input")));
ow_->StartObject("")->RenderString("ts", "Z")->EndObject(); ow_->StartObject("")->RenderString("ts", "Z")->EndObject();
CheckOutput(timestamp); CheckOutput(timestamp);
@ -884,10 +890,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) {
EXPECT_CALL( EXPECT_CALL(
listener_, listener_,
InvalidValue( InvalidValue(_,
_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
StringPiece("Field 'ts', Invalid time format, failed to parse nano " StringPiece("Field 'ts', Invalid time format: "
"seconds"))); "1970-01-01T00:00:00.ABZ")));
ow_->StartObject("") ow_->StartObject("")
->RenderString("ts", "1970-01-01T00:00:00.ABZ") ->RenderString("ts", "1970-01-01T00:00:00.ABZ")
@ -902,7 +908,8 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) {
listener_, listener_,
InvalidValue(_, InvalidValue(_,
StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
StringPiece("Field 'ts', Timestamp value exceeds limits"))); StringPiece("Field 'ts', Invalid time format: "
"-8032-10-18T00:00:00.000Z")));
ow_->StartObject("") ow_->StartObject("")
->RenderString("ts", "-8032-10-18T00:00:00.000Z") ->RenderString("ts", "-8032-10-18T00:00:00.000Z")
@ -1008,6 +1015,11 @@ class ProtoStreamObjectWriterStructTest
} }
}; };
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
ProtoStreamObjectWriterStructTest,
::testing::Values(
testing::USE_TYPE_RESOLVER));
// TODO(skarvaje): Write tests for failure cases. // TODO(skarvaje): Write tests for failure cases.
TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) { TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) {
StructType struct_type; StructType struct_type;
@ -1046,12 +1058,62 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) {
CheckOutput(struct_type); CheckOutput(struct_type);
} }
TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
EXPECT_CALL(
listener_,
InvalidName(_, StringPiece("k1"),
StringPiece("Repeated map key: 'k1' is already set.")));
ow_->StartObject("")
->StartObject("object")
->RenderString("k1", "v1")
->RenderString("k1", "v2")
->EndObject()
->EndObject();
}
TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) {
EXPECT_CALL(
listener_,
InvalidName(_, StringPiece("k1"),
StringPiece("Repeated map key: 'k1' is already set.")));
ow_->StartObject("")
->StartObject("object")
->RenderString("k1", "v1")
->StartList("k1")
->RenderString("", "v2")
->EndList()
->EndObject()
->EndObject();
}
TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) {
EXPECT_CALL(
listener_,
InvalidName(_, StringPiece("k1"),
StringPiece("Repeated map key: 'k1' is already set.")));
ow_->StartObject("")
->StartObject("object")
->StartObject("k1")
->RenderString("sub_k1", "v1")
->EndObject()
->StartObject("k1")
->RenderString("sub_k2", "v2")
->EndObject()
->EndObject()
->EndObject();
}
class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest {
protected: protected:
ProtoStreamObjectWriterMapTest() ProtoStreamObjectWriterMapTest()
: BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {} : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {}
}; };
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
ProtoStreamObjectWriterMapTest,
::testing::Values(
testing::USE_TYPE_RESOLVER));
TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
MapIn mm; MapIn mm;
EXPECT_CALL(listener_, EXPECT_CALL(listener_,
@ -1066,17 +1128,37 @@ TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
CheckOutput(mm); CheckOutput(mm);
} }
TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) {
EXPECT_CALL(
listener_,
InvalidName(_, StringPiece("k1"),
StringPiece("Repeated map key: 'k1' is already set.")));
ow_->StartObject("")
->RenderString("other", "test")
->StartObject("map_input")
->RenderString("k1", "v1")
->RenderString("k1", "v2")
->EndObject()
->EndObject();
}
class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
protected: protected:
ProtoStreamObjectWriterAnyTest() { ProtoStreamObjectWriterAnyTest() {
vector<const Descriptor*> descriptors; vector<const Descriptor*> descriptors;
descriptors.push_back(AnyOut::descriptor()); descriptors.push_back(AnyOut::descriptor());
descriptors.push_back(google::protobuf::DoubleValue::descriptor()); descriptors.push_back(google::protobuf::DoubleValue::descriptor());
descriptors.push_back(google::protobuf::Timestamp::descriptor());
descriptors.push_back(google::protobuf::Any::descriptor()); descriptors.push_back(google::protobuf::Any::descriptor());
ResetTypeInfo(descriptors); ResetTypeInfo(descriptors);
} }
}; };
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
ProtoStreamObjectWriterAnyTest,
::testing::Values(
testing::USE_TYPE_RESOLVER));
TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) {
AnyOut any; AnyOut any;
google::protobuf::Any* any_type = any.mutable_any(); google::protobuf::Any* any_type = any.mutable_any();
@ -1119,8 +1201,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) {
->EndObject() ->EndObject()
->EndObject() ->EndObject()
->EndObject(); ->EndObject();
CheckOutput(out, 115);
} }
TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
@ -1155,8 +1235,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
->EndObject() ->EndObject()
->EndObject() ->EndObject()
->EndObject(); ->EndObject();
CheckOutput(out, 159);
} }
TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
@ -1263,6 +1341,23 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) {
CheckOutput(any); CheckOutput(any);
} }
TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) {
EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
StringPiece("Invalid time format: ")));
AnyOut any;
google::protobuf::Any* any_type = any.mutable_any();
any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp");
ow_->StartObject("")
->StartObject("any")
->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
->RenderString("value", "")
->EndObject()
->EndObject();
CheckOutput(any);
}
class ProtoStreamObjectWriterFieldMaskTest class ProtoStreamObjectWriterFieldMaskTest
: public BaseProtoStreamObjectWriterTest { : public BaseProtoStreamObjectWriterTest {
protected: protected:
@ -1274,6 +1369,11 @@ class ProtoStreamObjectWriterFieldMaskTest
} }
}; };
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
ProtoStreamObjectWriterFieldMaskTest,
::testing::Values(
testing::USE_TYPE_RESOLVER));
TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) { TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) {
FieldMaskTest expected; FieldMaskTest expected;
expected.set_id("1"); expected.set_id("1");
@ -1683,6 +1783,7 @@ TEST_P(ProtoStreamObjectWriterOneOfsTest,
ow_->RenderString("strData", "blah"); ow_->RenderString("strData", "blah");
ow_->RenderInt32("intData", 123); ow_->RenderInt32("intData", 123);
ow_->EndObject(); ow_->EndObject();
ow_->EndObject();
} }
} // namespace converter } // namespace converter

@ -298,16 +298,21 @@ bool IsMap(const google::protobuf::Field& field,
"google.protobuf.MessageOptions.map_entry", false)); "google.protobuf.MessageOptions.map_entry", false));
} }
bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
return GetBoolOptionOrDefault(
type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false);
}
string DoubleAsString(double value) { string DoubleAsString(double value) {
if (google::protobuf::MathLimits<double>::IsPosInf(value)) return "Infinity"; if (MathLimits<double>::IsPosInf(value)) return "Infinity";
if (google::protobuf::MathLimits<double>::IsNegInf(value)) return "-Infinity"; if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
if (google::protobuf::MathLimits<double>::IsNaN(value)) return "NaN"; if (MathLimits<double>::IsNaN(value)) return "NaN";
return SimpleDtoa(value); return SimpleDtoa(value);
} }
string FloatAsString(float value) { string FloatAsString(float value) {
if (google::protobuf::MathLimits<float>::IsFinite(value)) return SimpleFtoa(value); if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
return DoubleAsString(value); return DoubleAsString(value);
} }
@ -318,7 +323,7 @@ bool SafeStrToFloat(StringPiece str, float *value) {
} }
*value = static_cast<float>(double_value); *value = static_cast<float>(double_value);
if (google::protobuf::MathLimits<float>::IsInf(*value)) { if (MathLimits<float>::IsInf(*value)) {
return false; return false;
} }
return true; return true;

@ -138,9 +138,6 @@ const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
const google::protobuf::Enum* enum_type, int32 value); const google::protobuf::Enum* enum_type, int32 value);
// Converts input to camel-case and returns it. // Converts input to camel-case and returns it.
// Tests are in wrappers/translator/snake2camel_objectwriter_test.cc
// TODO(skarvaje): Isolate tests for this function and put them in
// utility_test.cc
LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input); LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input);
// Converts input to snake_case and returns it. // Converts input to snake_case and returns it.
@ -157,6 +154,9 @@ LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string);
LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field, LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field,
const google::protobuf::Type& type); const google::protobuf::Type& type);
// Returns true if the given type has special MessageSet wire format.
bool IsMessageSetWireFormat(const google::protobuf::Type& type);
// Infinity/NaN-aware conversion to string. // Infinity/NaN-aware conversion to string.
LIBPROTOBUF_EXPORT string DoubleAsString(double value); LIBPROTOBUF_EXPORT string DoubleAsString(double value);
LIBPROTOBUF_EXPORT string FloatAsString(float value); LIBPROTOBUF_EXPORT string FloatAsString(float value);

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

Loading…
Cancel
Save