Merge pull request #5332 from acozzette/integrate
Integrated internal changes from Google
diff --git a/BUILD b/BUILD
index 0130f55..80ae3e5 100644
--- a/BUILD
+++ b/BUILD
@@ -347,7 +347,6 @@
"src/google/protobuf/compiler/plugin.pb.cc",
"src/google/protobuf/compiler/python/python_generator.cc",
"src/google/protobuf/compiler/ruby/ruby_generator.cc",
- "src/google/protobuf/compiler/scc.cc",
"src/google/protobuf/compiler/subprocess.cc",
"src/google/protobuf/compiler/zip_writer.cc",
],
diff --git a/Makefile.am b/Makefile.am
index 0c86b93..309840a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1039,6 +1039,11 @@
js/test8.proto \
js/test9.proto \
js/test10.proto \
+ js/test11.proto \
+ js/test12.proto \
+ js/test13.proto \
+ js/test14.proto \
+ js/test15.proto \
js/test_bootstrap.js \
js/testbinary.proto \
js/testempty.proto
@@ -1084,14 +1089,17 @@
examples/README.md \
examples/WORKSPACE \
examples/add_person.cc \
+ examples/add_person.dart \
examples/add_person.go \
examples/add_person.py \
examples/add_person_test.go \
examples/addressbook.proto \
examples/list_people.cc \
+ examples/list_people.dart \
examples/list_people.go \
examples/list_people.py \
examples/list_people_test.go \
+ examples/pubspec.yaml \
protobuf.bzl \
python/release/wheel/build_wheel_manylinux.sh \
python/release/wheel/Dockerfile \
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index 850a85a..063fc3d 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -78,7 +78,6 @@
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
- ${protobuf_source_dir}/src/google/protobuf/compiler/scc.cc
${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
)
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 6995067..7affb95 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
index 9e37e9d..524ac06 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -113,7 +113,7 @@
/// 01:30 UTC on January 15, 2017.
///
/// In JavaScript, one can convert a Date object to this format using the
- /// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+ /// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
/// method. In Python, a standard `datetime.datetime` object can be converted
/// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
/// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 2c8929e..3c168e6 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -46,7 +46,6 @@
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
-
static {
EMPTY_LIST.makeImmutable();
}
@@ -237,7 +236,7 @@
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
- System.arraycopy(array, i + 1, array, i, size - i);
+ System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
@@ -252,7 +251,7 @@
ensureIndexInRange(index);
boolean value = array[index];
if (index < size - 1) {
- System.arraycopy(array, index + 1, array, index, size - index);
+ System.arraycopy(array, index + 1, array, index, size - index - 1);
}
size--;
modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
index 844d8a5..eca9ef1 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -147,14 +147,23 @@
public abstract byte byteAt(int index);
/**
+ * Gets the byte at the given index, assumes bounds checking has already been performed.
+ *
+ * @param index index of byte
+ * @return the value
+ * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
+ */
+ abstract byte internalByteAt(int index);
+
+ /**
* Return a {@link ByteString.ByteIterator} over the bytes in the ByteString. To avoid
* auto-boxing, you may get the iterator manually and call {@link ByteIterator#nextByte()}.
*
* @return the iterator
*/
@Override
- public final ByteIterator iterator() {
- return new ByteIterator() {
+ public ByteIterator iterator() {
+ return new AbstractByteIterator() {
private int position = 0;
private final int limit = size();
@@ -164,23 +173,13 @@
}
@Override
- public Byte next() {
- // Boxing calls Byte.valueOf(byte), which does not instantiate.
- return nextByte();
- }
-
- @Override
public byte nextByte() {
- try {
- return byteAt(position++);
- } catch (IndexOutOfBoundsException e) {
- throw new NoSuchElementException(e.getMessage());
+ int currentPos = position;
+ if (currentPos >= limit) {
+ throw new NoSuchElementException();
}
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
+ position = currentPos + 1;
+ return internalByteAt(currentPos);
}
};
}
@@ -198,6 +197,19 @@
byte nextByte();
}
+ abstract static class AbstractByteIterator implements ByteIterator {
+ @Override
+ public final Byte next() {
+ // Boxing calls Byte.valueOf(byte), which does not instantiate.
+ return nextByte();
+ }
+
+ @Override
+ public final void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
/**
* Gets the number of bytes.
*
@@ -1281,6 +1293,11 @@
}
@Override
+ byte internalByteAt(int index) {
+ return bytes[index];
+ }
+
+ @Override
public int size() {
return bytes.length;
}
@@ -1522,6 +1539,11 @@
}
@Override
+ byte internalByteAt(int index) {
+ return bytes[bytesOffset + index];
+ }
+
+ @Override
public int size() {
return bytesLength;
}
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index df4cc66..161a1b6 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -2783,7 +2783,8 @@
sizeLimit - totalBytesRetired - bufferSize));
if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
throw new IllegalStateException(
- "InputStream#read(byte[]) returned invalid result: "
+ input.getClass()
+ + "#read(byte[]) returned invalid result: "
+ bytesRead
+ "\nThe InputStream implementation is buggy.");
}
@@ -3005,20 +3006,46 @@
throw InvalidProtocolBufferException.truncatedMessage();
}
- // Skipping more bytes than are in the buffer. First skip what we have.
- int tempPos = bufferSize - pos;
- pos = bufferSize;
-
- // Keep refilling the buffer until we get to the point we wanted to skip to.
- // This has the side effect of ensuring the limits are updated correctly.
- refillBuffer(1);
- while (size - tempPos > bufferSize) {
- tempPos += bufferSize;
+ if (refillCallback != null) {
+ // Skipping more bytes than are in the buffer. First skip what we have.
+ int tempPos = bufferSize - pos;
pos = bufferSize;
- refillBuffer(1);
- }
- pos = size - tempPos;
+ // Keep refilling the buffer until we get to the point we wanted to skip to.
+ // This has the side effect of ensuring the limits are updated correctly.
+ refillBuffer(1);
+ while (size - tempPos > bufferSize) {
+ tempPos += bufferSize;
+ pos = bufferSize;
+ refillBuffer(1);
+ }
+
+ pos = size - tempPos;
+ } else {
+ // Skipping more bytes than are in the buffer. First skip what we have.
+ totalBytesRetired += pos;
+ int totalSkipped = bufferSize - pos;
+ bufferSize = 0;
+ pos = 0;
+
+ try {
+ while (totalSkipped < size) {
+ int toSkip = size - totalSkipped;
+ long skipped = input.skip(toSkip);
+ if (skipped < 0 || skipped > toSkip) {
+ throw new IllegalStateException(
+ input.getClass()
+ + "#skip returned invalid result: "
+ + skipped
+ + "\nThe InputStream implementation is buggy.");
+ }
+ totalSkipped += (int) skipped;
+ }
+ } finally {
+ totalBytesRetired += totalSkipped;
+ recomputeBufferSizeAfterLimit();
+ }
+ }
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index e7b8fa8..d0fa9b7 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -46,7 +46,6 @@
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
-
static {
EMPTY_LIST.makeImmutable();
}
@@ -104,7 +103,7 @@
final double[] arr = other.array;
for (int i = 0; i < size; i++) {
- if (array[i] != arr[i]) {
+ if (Double.doubleToLongBits(array[i]) != Double.doubleToLongBits(arr[i])) {
return false;
}
}
@@ -237,7 +236,7 @@
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
- System.arraycopy(array, i + 1, array, i, size - i);
+ System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
@@ -252,7 +251,7 @@
ensureIndexInRange(index);
double value = array[index];
if (index < size - 1) {
- System.arraycopy(array, index + 1, array, index, size - index);
+ System.arraycopy(array, index + 1, array, index, size - index - 1);
}
size--;
modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 85e09be..62330c3 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -46,7 +46,6 @@
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
-
static {
EMPTY_LIST.makeImmutable();
}
@@ -104,7 +103,7 @@
final float[] arr = other.array;
for (int i = 0; i < size; i++) {
- if (array[i] != arr[i]) {
+ if (Float.floatToIntBits(array[i]) != Float.floatToIntBits(arr[i])) {
return false;
}
}
@@ -236,7 +235,7 @@
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
- System.arraycopy(array, i + 1, array, i, size - i);
+ System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
@@ -251,7 +250,7 @@
ensureIndexInRange(index);
float value = array[index];
if (index < size - 1) {
- System.arraycopy(array, index + 1, array, index, size - index);
+ System.arraycopy(array, index + 1, array, index, size - index - 1);
}
size--;
modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 0034c58..619ef09 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -451,16 +451,18 @@
}
@Override
- public BuilderType mergeFrom(byte[] input, int offset, int length)
+ public BuilderType mergeFrom(
+ byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// BEGIN REGULAR
- return super.mergeFrom(input, offset, length);
+ return super.mergeFrom(input, offset, length, extensionRegistry);
// END REGULAR
// BEGIN EXPERIMENTAL
// copyOnWrite();
// try {
// Protobuf.getInstance().schemaFor(instance).mergeFrom(
- // instance, input, offset, offset + length, new ArrayDecoders.Registers());
+ // instance, input, offset, offset + length,
+ // new ArrayDecoders.Registers(extensionRegistry));
// } catch (InvalidProtocolBufferException e) {
// throw e;
// } catch (IndexOutOfBoundsException e) {
@@ -474,6 +476,18 @@
@Override
public BuilderType mergeFrom(
+ byte[] input, int offset, int length)
+ throws InvalidProtocolBufferException {
+ // BEGIN REGULAR
+ return super.mergeFrom(input, offset, length);
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // return mergeFrom(input, offset, length, ExtensionRegistryLite.getEmptyRegistry());
+ // END EXPERIMENTAL
+ }
+
+ @Override
+ public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws IOException {
@@ -483,6 +497,8 @@
instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR
// BEGIN EXPERIMENTAL
+ // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
+ // // fast path.
// Protobuf.getInstance().schemaFor(instance).mergeFrom(
// instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL
@@ -814,7 +830,7 @@
.setField(extension.descriptor, extension.singularToFieldSetType(value));
}
- private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+ FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
if (extensions.isImmutable()) {
extensions = extensions.clone();
}
@@ -1558,8 +1574,11 @@
}
@Override
- public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException {
- return GeneratedMessageLite.parsePartialFrom(defaultInstance, input);
+ public T parsePartialFrom(
+ byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return GeneratedMessageLite.parsePartialFrom(
+ defaultInstance, input, offset, length, extensionRegistry);
}
}
@@ -1578,6 +1597,8 @@
result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR
// BEGIN EXPERIMENTAL
+ // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
+ // // fast path.
// Protobuf.getInstance().schemaFor(result).mergeFrom(
// result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL
@@ -1599,17 +1620,31 @@
}
/** A static helper method for parsing a partial from byte array. */
- static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input)
+ static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+ T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// BEGIN REGULAR
- return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry());
+ T message;
+ try {
+ CodedInputStream cis = CodedInputStream.newInstance(input, offset, length);
+ message = parsePartialFrom(instance, cis, extensionRegistry);
+ try {
+ cis.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
// END REGULAR
// BEGIN EXPERIMENTAL
// @SuppressWarnings("unchecked") // Guaranteed by protoc
// T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
// try {
// Protobuf.getInstance().schemaFor(result).mergeFrom(
- // result, input, 0, input.length, new ArrayDecoders.Registers());
+ // result, input, offset, offset + length,
+ // new ArrayDecoders.Registers(extensionRegistry));
// result.makeImmutable();
// if (result.memoizedHashCode != 0) {
// throw new RuntimeException();
@@ -1701,32 +1736,23 @@
private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
- T message;
- try {
- CodedInputStream input = CodedInputStream.newInstance(data);
- message = parsePartialFrom(defaultInstance, input, extensionRegistry);
- try {
- input.checkLastTagWas(0);
- } catch (InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(message);
- }
- return message;
- } catch (InvalidProtocolBufferException e) {
- throw e;
- }
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
}
// Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data) throws InvalidProtocolBufferException {
- return checkMessageInitialized(parsePartialFrom(defaultInstance, data));
+ return checkMessageInitialized(parsePartialFrom(
+ defaultInstance, data, 0, data.length, ExtensionRegistryLite.getEmptyRegistry()));
}
// Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
- return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
}
// Does not validate last tag.
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index c9b12c4..ad128b5 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -46,7 +46,6 @@
implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
private static final IntArrayList EMPTY_LIST = new IntArrayList();
-
static {
EMPTY_LIST.makeImmutable();
}
@@ -236,7 +235,7 @@
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
- System.arraycopy(array, i + 1, array, i, size - i);
+ System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
@@ -251,7 +250,7 @@
ensureIndexInRange(index);
int value = array[index];
if (index < size - 1) {
- System.arraycopy(array, index + 1, array, index, size - index);
+ System.arraycopy(array, index + 1, array, index, size - index - 1);
}
size--;
modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index 8cdab12..99f7fdb 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -46,7 +46,6 @@
implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
private static final LongArrayList EMPTY_LIST = new LongArrayList();
-
static {
EMPTY_LIST.makeImmutable();
}
@@ -236,7 +235,7 @@
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
- System.arraycopy(array, i + 1, array, i, size - i);
+ System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
@@ -251,7 +250,7 @@
ensureIndexInRange(index);
long value = array[index];
if (index < size - 1) {
- System.arraycopy(array, index + 1, array, index, size - index);
+ System.arraycopy(array, index + 1, array, index, size - index - 1);
}
size--;
modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
index 52b4a20..08f6244 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -149,8 +149,12 @@
Descriptors.Descriptor getDescriptorForType();
/**
- * Create a Builder for messages of the appropriate type for the given field. Messages built
- * with this can then be passed to setField(), setRepeatedField(), or addRepeatedField().
+ * Create a builder for messages of the appropriate type for the given field. The
+ * builder is NOT nested in the current builder. However, messages built with the
+ * builder can then be passed to the {@link #setField()}, {@link #setRepeatedField()}, or {@link
+ * #addRepeatedField()} method of the current builder.
+ *
+ * <p>To obtain a builder nested in the current builder, use {@link #getFieldBuilder()} instead.
*/
Builder newBuilderForField(Descriptors.FieldDescriptor field);
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index 9fc72bd..cbcf938 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -334,6 +334,14 @@
MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance);
+ /**
+ * Returns an empty merge target for a sub-field. When defaultInstance is provided, it indicates
+ * the descriptor is for an extension type, and implementations should create a new instance
+ * from the defaultInstance prototype directly.
+ */
+ MergeTarget newEmptyTargetForField(
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance);
+
/** Finishes the merge and returns the underlying object. */
Object finish();
}
@@ -494,11 +502,31 @@
@Override
public MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor field, Message defaultInstance) {
+ Message.Builder subBuilder;
if (defaultInstance != null) {
- return new BuilderAdapter(defaultInstance.newBuilderForType());
+ subBuilder = defaultInstance.newBuilderForType();
} else {
- return new BuilderAdapter(builder.newBuilderForField(field));
+ subBuilder = builder.newBuilderForField(field);
}
+ if (!field.isRepeated()) {
+ Message originalMessage = (Message) getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ }
+ return new BuilderAdapter(subBuilder);
+ }
+
+ @Override
+ public MergeTarget newEmptyTargetForField(
+ Descriptors.FieldDescriptor field, Message defaultInstance) {
+ Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ return new BuilderAdapter(subBuilder);
}
@Override
@@ -662,6 +690,12 @@
}
@Override
+ public MergeTarget newEmptyTargetForField(
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
+ throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object");
+ }
+
+ @Override
public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) {
return WireFormat.Utf8Validation.STRICT;
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
index 64de6b1..64c46be 100644
--- a/java/core/src/main/java/com/google/protobuf/NioByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -82,6 +82,13 @@
}
@Override
+ public byte internalByteAt(int index) {
+ // it isn't possible to avoid the bounds checking inside of ByteBuffer, so just use the default
+ // implementation.
+ return byteAt(index);
+ }
+
+ @Override
public int size() {
return buffer.remaining();
}
diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
index 154fd5d..140cbe4 100644
--- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -38,12 +38,12 @@
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Stack;
/**
* Class to represent {@code ByteStrings} formed by concatenation of other ByteStrings, without
@@ -240,13 +240,17 @@
@Override
public byte byteAt(int index) {
checkIndex(index, totalLength);
+ return internalByteAt(index);
+ }
+ @Override
+ byte internalByteAt(int index) {
// Find the relevant piece by recursive descent
if (index < leftLength) {
- return left.byteAt(index);
+ return left.internalByteAt(index);
}
- return right.byteAt(index - leftLength);
+ return right.internalByteAt(index - leftLength);
}
@Override
@@ -254,6 +258,37 @@
return totalLength;
}
+ @Override
+ public ByteIterator iterator() {
+ return new AbstractByteIterator() {
+ final PieceIterator pieces = new PieceIterator(RopeByteString.this);
+ ByteIterator current = nextPiece();
+
+ private ByteIterator nextPiece() {
+ // NOTE: PieceIterator is guaranteed to return non-empty pieces, so this method will always
+ // return non-empty iterators (or null)
+ return pieces.hasNext() ? pieces.next().iterator() : null;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return current != null;
+ }
+
+ @Override
+ public byte nextByte() {
+ if (current == null) {
+ throw new NoSuchElementException();
+ }
+ byte b = current.nextByte();
+ if (!current.hasNext()) {
+ current = nextPiece();
+ }
+ return b;
+ }
+ };
+ }
+
// =================================================================
// Pieces
@@ -546,7 +581,7 @@
// Stack containing the part of the string, starting from the left, that
// we've already traversed. The final string should be the equivalent of
// concatenating the strings on the stack from bottom to top.
- private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
+ private final ArrayDeque<ByteString> prefixesStack = new ArrayDeque<>();
private ByteString balance(ByteString left, ByteString right) {
doBalance(left);
@@ -650,9 +685,8 @@
*
* <p>This iterator is used to implement {@link RopeByteString#equalsFragments(ByteString)}.
*/
- private static class PieceIterator implements Iterator<LeafByteString> {
-
- private final Stack<RopeByteString> breadCrumbs = new Stack<RopeByteString>();
+ private static final class PieceIterator implements Iterator<LeafByteString> {
+ private final ArrayDeque<RopeByteString> breadCrumbs = new ArrayDeque<>();
private LeafByteString next;
private PieceIterator(ByteString root) {
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index f89768a..aaea097 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -1127,6 +1127,7 @@
PARSER.merge(input, builder);
}
+
/**
* Parse a text-format message from {@code input}.
*
@@ -1166,6 +1167,7 @@
PARSER.merge(input, extensionRegistry, builder);
}
+
/**
* Parse a text-format message from {@code input}. Extensions will be recognized if they are
* registered in {@code extensionRegistry}.
@@ -1185,6 +1187,7 @@
}
+
/**
* Parser for text-format proto2 instances. This class is thread-safe. The implementation largely
* follows google/protobuf/text_format.cc.
@@ -1205,24 +1208,60 @@
* </ul>
*/
public enum SingularOverwritePolicy {
- /** The last value is retained. */
+ /**
+ * Later values are merged with earlier values. For primitive fields or conflicting oneofs,
+ * the last value is retained.
+ */
ALLOW_SINGULAR_OVERWRITES,
/** An error is issued. */
FORBID_SINGULAR_OVERWRITES
}
+ /**
+ * Determines how to deal with repeated values for singular Message fields. For example,
+ * given a field "foo" containing subfields "baz" and "qux":
+ *
+ * <ul>
+ * <li>"foo { baz: 1 } foo { baz: 2 }", or
+ * <li>"foo { baz: 1 } foo { qux: 2 }"
+ * </ul>
+ */
+ public enum MergingStyle {
+ /**
+ * Merge the values in standard protobuf fashion:
+ *
+ * <ul>
+ * <li>"foo { baz: 2 }" and
+ * <li>"foo { baz: 1, qux: 2 }", respectively.
+ * </ul>
+ */
+ RECURSIVE,
+ /**
+ * Later values overwrite ("clobber") previous values:
+ *
+ * <ul>
+ * <li>"foo { baz: 2 }" and
+ * <li>"foo { qux: 2 }", respectively.
+ * </ul>
+ */
+ NON_RECURSIVE
+ }
+
private final boolean allowUnknownFields;
private final boolean allowUnknownEnumValues;
+ private final boolean allowUnknownExtensions;
private final SingularOverwritePolicy singularOverwritePolicy;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
private Parser(
boolean allowUnknownFields,
boolean allowUnknownEnumValues,
+ boolean allowUnknownExtensions,
SingularOverwritePolicy singularOverwritePolicy,
TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
this.allowUnknownFields = allowUnknownFields;
this.allowUnknownEnumValues = allowUnknownEnumValues;
+ this.allowUnknownExtensions = allowUnknownExtensions;
this.singularOverwritePolicy = singularOverwritePolicy;
this.parseInfoTreeBuilder = parseInfoTreeBuilder;
}
@@ -1236,11 +1275,23 @@
public static class Builder {
private boolean allowUnknownFields = false;
private boolean allowUnknownEnumValues = false;
+ private boolean allowUnknownExtensions = false;
private SingularOverwritePolicy singularOverwritePolicy =
SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
+ /**
+ * Set whether this parser will allow unknown extensions. By default, an
+ * exception is thrown if unknown extension is encountered. If this is set true,
+ * the parser will only log a warning. Allow unknown extensions does not mean
+ * allow normal unknown fields.
+ */
+ public Builder setAllowUnknownExtensions(boolean allowUnknownExtensions) {
+ this.allowUnknownExtensions = allowUnknownExtensions;
+ return this;
+ }
+
/** Sets parser behavior when a non-repeated field appears more than once. */
public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
this.singularOverwritePolicy = p;
@@ -1256,6 +1307,7 @@
return new Parser(
allowUnknownFields,
allowUnknownEnumValues,
+ allowUnknownExtensions,
singularOverwritePolicy,
parseInfoTreeBuilder);
}
@@ -1297,6 +1349,7 @@
}
+
private static final int BUFFER_SIZE = 4096;
// TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
@@ -1315,25 +1368,56 @@
return text;
}
+ static final class UnknownField {
+ static enum Type {
+ FIELD, EXTENSION;
+ }
+
+ final String message;
+ final Type type;
+
+ UnknownField(String message, Type type) {
+ this.message = message;
+ this.type = type;
+ }
+ }
+
// Check both unknown fields and unknown extensions and log warning messages
// or throw exceptions according to the flag.
- private void checkUnknownFields(final List<String> unknownFields) throws ParseException {
+ private void checkUnknownFields(final List<UnknownField> unknownFields) throws ParseException {
if (unknownFields.isEmpty()) {
return;
}
StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:");
- for (String field : unknownFields) {
- msg.append('\n').append(field);
+ for (UnknownField field : unknownFields) {
+ msg.append('\n').append(field.message);
}
if (allowUnknownFields) {
logger.warning(msg.toString());
- } else {
- String[] lineColumn = unknownFields.get(0).split(":");
- throw new ParseException(
- Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
+ return;
}
+
+ int firstErrorIndex = 0;
+ if (allowUnknownExtensions) {
+ boolean allUnknownExtensions = true;
+ for (UnknownField field : unknownFields) {
+ if (field.type == UnknownField.Type.FIELD) {
+ allUnknownExtensions = false;
+ break;
+ }
+ ++firstErrorIndex;
+ }
+ if (allUnknownExtensions) {
+ logger.warning(msg.toString());
+ return;
+ }
+ }
+
+ String[] lineColumn = unknownFields.get(firstErrorIndex).message.split(":");
+ throw new ParseException(
+ Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
}
/**
@@ -1348,24 +1432,32 @@
final Tokenizer tokenizer = new Tokenizer(input);
MessageReflection.BuilderAdapter target = new MessageReflection.BuilderAdapter(builder);
- List<String> unknownFields = new ArrayList<String>();
+ List<UnknownField> unknownFields = new ArrayList<UnknownField>();
while (!tokenizer.atEnd()) {
- mergeField(tokenizer, extensionRegistry, target, unknownFields);
+ mergeField(tokenizer, extensionRegistry, target, MergingStyle.RECURSIVE, unknownFields);
}
checkUnknownFields(unknownFields);
}
+
/** Parse a single field from {@code tokenizer} and merge it into {@code builder}. */
private void mergeField(
final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target,
- List<String> unknownFields)
+ final MergingStyle mergingStyle,
+ List<UnknownField> unknownFields)
throws ParseException {
- mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, unknownFields);
+ mergeField(
+ tokenizer,
+ extensionRegistry,
+ target,
+ parseInfoTreeBuilder,
+ mergingStyle,
+ unknownFields);
}
/** Parse a single field from {@code tokenizer} and merge it into {@code target}. */
@@ -1374,7 +1466,8 @@
final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target,
TextFormatParseInfoTree.Builder parseTreeBuilder,
- List<String> unknownFields)
+ final MergingStyle mergingStyle,
+ List<UnknownField> unknownFields)
throws ParseException {
FieldDescriptor field = null;
int startLine = tokenizer.getLine();
@@ -1393,15 +1486,15 @@
extension = target.findExtensionByName(extensionRegistry, name.toString());
if (extension == null) {
- unknownFields.add(
- (tokenizer.getPreviousLine() + 1)
- + ":"
- + (tokenizer.getPreviousColumn() + 1)
- + ":\t"
- + type.getFullName()
- + ".["
- + name
- + "]");
+ String message = (tokenizer.getPreviousLine() + 1)
+ + ":"
+ + (tokenizer.getPreviousColumn() + 1)
+ + ":\t"
+ + type.getFullName()
+ + ".["
+ + name
+ + "]";
+ unknownFields.add(new UnknownField(message, UnknownField.Type.EXTENSION));
} else {
if (extension.descriptor.getContainingType() != type) {
throw tokenizer.parseExceptionPreviousToken(
@@ -1440,14 +1533,14 @@
}
if (field == null) {
- unknownFields.add(
- (tokenizer.getPreviousLine() + 1)
- + ":"
- + (tokenizer.getPreviousColumn() + 1)
- + ":\t"
- + type.getFullName()
- + "."
- + name);
+ String message = (tokenizer.getPreviousLine() + 1)
+ + ":"
+ + (tokenizer.getPreviousColumn() + 1)
+ + ":\t"
+ + type.getFullName()
+ + "."
+ + name;
+ unknownFields.add(new UnknownField(message, UnknownField.Type.FIELD));
}
}
@@ -1480,6 +1573,7 @@
field,
extension,
childParseTreeBuilder,
+ mergingStyle,
unknownFields);
} else {
consumeFieldValues(
@@ -1489,6 +1583,7 @@
field,
extension,
parseTreeBuilder,
+ mergingStyle,
unknownFields);
}
} else {
@@ -1500,6 +1595,7 @@
field,
extension,
parseTreeBuilder,
+ mergingStyle,
unknownFields);
}
@@ -1524,7 +1620,8 @@
final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension,
final TextFormatParseInfoTree.Builder parseTreeBuilder,
- List<String> unknownFields)
+ final MergingStyle mergingStyle,
+ List<UnknownField> unknownFields)
throws ParseException {
// Support specifying repeated field values as a comma-separated list.
// Ex."foo: [1, 2, 3]"
@@ -1538,6 +1635,7 @@
field,
extension,
parseTreeBuilder,
+ mergingStyle,
unknownFields);
if (tokenizer.tryConsume("]")) {
// End of list.
@@ -1554,6 +1652,7 @@
field,
extension,
parseTreeBuilder,
+ mergingStyle,
unknownFields);
}
}
@@ -1566,8 +1665,28 @@
final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension,
final TextFormatParseInfoTree.Builder parseTreeBuilder,
- List<String> unknownFields)
+ final MergingStyle mergingStyle,
+ List<UnknownField> unknownFields)
throws ParseException {
+ if (singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES
+ && !field.isRepeated()) {
+ if (target.hasField(field)) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
+ } else if (field.getContainingOneof() != null
+ && target.hasOneof(field.getContainingOneof())) {
+ Descriptors.OneofDescriptor oneof = field.getContainingOneof();
+ throw tokenizer.parseExceptionPreviousToken(
+ "Field \""
+ + field.getFullName()
+ + "\" is specified along with field \""
+ + target.getOneofFieldDescriptor(oneof).getFullName()
+ + "\", another member of oneof \""
+ + oneof.getName()
+ + "\".");
+ }
+ }
+
Object value = null;
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
@@ -1580,15 +1699,29 @@
}
final MessageReflection.MergeTarget subField;
- subField =
- target.newMergeTargetForField(
- field, (extension == null) ? null : extension.defaultInstance);
+ Message defaultInstance = (extension == null) ? null : extension.defaultInstance;
+ switch (mergingStyle) {
+ case RECURSIVE:
+ subField = target.newMergeTargetForField(field, defaultInstance);
+ break;
+ case NON_RECURSIVE:
+ subField = target.newEmptyTargetForField(field, defaultInstance);
+ break;
+ default:
+ throw new AssertionError();
+ }
while (!tokenizer.tryConsume(endToken)) {
if (tokenizer.atEnd()) {
throw tokenizer.parseException("Expected \"" + endToken + "\".");
}
- mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, unknownFields);
+ mergeField(
+ tokenizer,
+ extensionRegistry,
+ subField,
+ parseTreeBuilder,
+ mergingStyle,
+ unknownFields);
}
value = subField.finish();
@@ -1693,22 +1826,6 @@
// TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
// check for duplicate map keys here.
target.addRepeatedField(field, value);
- } else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
- && target.hasField(field)) {
- throw tokenizer.parseExceptionPreviousToken(
- "Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
- } else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
- && field.getContainingOneof() != null
- && target.hasOneof(field.getContainingOneof())) {
- Descriptors.OneofDescriptor oneof = field.getContainingOneof();
- throw tokenizer.parseExceptionPreviousToken(
- "Field \""
- + field.getFullName()
- + "\" is specified along with field \""
- + target.getOneofFieldDescriptor(oneof).getFullName()
- + "\", another member of oneof \""
- + oneof.getName()
- + "\".");
} else {
target.setField(field, value);
}
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
index 50bc911..17df54a 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -83,6 +83,15 @@
}
+ @SuppressWarnings("unchecked") // safe by method contract
+ static <T> T allocateInstance(Class<T> clazz) {
+ try {
+ return (T) UNSAFE.allocateInstance(clazz);
+ } catch (InstantiationException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
static long objectFieldOffset(Field field) {
return MEMORY_ACCESSOR.objectFieldOffset(field);
}
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
index 1020c69..cc979ac 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -522,8 +522,8 @@
/**
* Asserts that the given protos are not equal and have different hash codes.
*
- * @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
- * than it needs to be. However, this should happen relatively rarely.
+ * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
+ * stricter than it needs to be. However, this should happen relatively rarely.
*/
private void checkNotEqual(Message m1, Message m2) {
String equalsError = String.format("%s should not be equal to %s", m1, m2);
diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
index 2fe04a9..d660ca7 100644
--- a/java/core/src/test/java/com/google/protobuf/AnyTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -35,17 +35,14 @@
import java.util.Objects;
import junit.framework.TestCase;
-/**
- * Unit tests for Any message.
- */
+/** Unit tests for Any message. */
public class AnyTest extends TestCase {
public void testAnyGeneratedApi() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder);
TestAllTypes message = builder.build();
- TestAny container = TestAny.newBuilder()
- .setValue(Any.pack(message)).build();
+ TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class));
@@ -64,8 +61,7 @@
// Test that unpacking throws an exception if parsing fails.
TestAny.Builder containerBuilder = container.toBuilder();
- containerBuilder.getValueBuilder().setValue(
- ByteString.copyFrom(new byte[]{0x11}));
+ containerBuilder.getValueBuilder().setValue(ByteString.copyFrom(new byte[] {0x11}));
container = containerBuilder.build();
try {
container.getValue().unpack(TestAllTypes.class);
@@ -80,12 +76,10 @@
TestUtil.setAllFields(builder);
TestAllTypes message = builder.build();
- TestAny container = TestAny.newBuilder()
- .setValue(Any.pack(message, "xxx.com")).build();
+ TestAny container = TestAny.newBuilder().setValue(Any.pack(message, "xxx.com")).build();
assertEquals(
- "xxx.com/" + TestAllTypes.getDescriptor().getFullName(),
- container.getValue().getTypeUrl());
+ "xxx.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class));
@@ -93,12 +87,10 @@
TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
TestUtil.assertAllFieldsSet(result);
- container = TestAny.newBuilder()
- .setValue(Any.pack(message, "yyy.com/")).build();
+ container = TestAny.newBuilder().setValue(Any.pack(message, "yyy.com/")).build();
assertEquals(
- "yyy.com/" + TestAllTypes.getDescriptor().getFullName(),
- container.getValue().getTypeUrl());
+ "yyy.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class));
@@ -106,12 +98,10 @@
result = container.getValue().unpack(TestAllTypes.class);
TestUtil.assertAllFieldsSet(result);
- container = TestAny.newBuilder()
- .setValue(Any.pack(message, "")).build();
+ container = TestAny.newBuilder().setValue(Any.pack(message, "")).build();
assertEquals(
- "/" + TestAllTypes.getDescriptor().getFullName(),
- container.getValue().getTypeUrl());
+ "/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class));
@@ -125,8 +115,7 @@
TestUtil.setAllFields(builder);
TestAllTypes message = builder.build();
- TestAny container = TestAny.newBuilder()
- .setValue(Any.pack(message)).build();
+ TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
assertTrue(container.getValue().is(TestAllTypes.class));
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index 8ef8edd..ae50071 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -77,10 +77,10 @@
list.addAll(asList(true, false, true, false));
Iterator<Boolean> iterator = list.iterator();
assertEquals(4, list.size());
- assertTrue(list.get(0));
- assertTrue(iterator.next());
+ assertEquals(true, (boolean) list.get(0));
+ assertEquals(true, (boolean) iterator.next());
list.set(0, true);
- assertFalse(iterator.next());
+ assertEquals(false, (boolean) iterator.next());
list.remove(0);
try {
@@ -101,9 +101,9 @@
}
public void testGet() {
- assertTrue(TERTIARY_LIST.get(0));
- assertFalse(TERTIARY_LIST.get(1));
- assertTrue(TERTIARY_LIST.get(2));
+ assertEquals(true, (boolean) TERTIARY_LIST.get(0));
+ assertEquals(false, (boolean) TERTIARY_LIST.get(1));
+ assertEquals(true, (boolean) TERTIARY_LIST.get(2));
try {
TERTIARY_LIST.get(-1);
@@ -121,9 +121,9 @@
}
public void testGetBoolean() {
- assertTrue(TERTIARY_LIST.getBoolean(0));
- assertFalse(TERTIARY_LIST.getBoolean(1));
- assertTrue(TERTIARY_LIST.getBoolean(2));
+ assertEquals(true, TERTIARY_LIST.getBoolean(0));
+ assertEquals(false, TERTIARY_LIST.getBoolean(1));
+ assertEquals(true, TERTIARY_LIST.getBoolean(2));
try {
TERTIARY_LIST.get(-1);
@@ -162,11 +162,11 @@
list.addBoolean(false);
list.addBoolean(false);
- assertFalse(list.set(0, true));
- assertTrue(list.getBoolean(0));
+ assertEquals(false, (boolean) list.set(0, true));
+ assertEquals(true, list.getBoolean(0));
- assertFalse(list.set(1, false));
- assertFalse(list.getBoolean(1));
+ assertEquals(false, (boolean) list.set(1, false));
+ assertEquals(false, list.getBoolean(1));
try {
list.set(-1, false);
@@ -187,11 +187,11 @@
list.addBoolean(true);
list.addBoolean(true);
- assertTrue(list.setBoolean(0, false));
- assertFalse(list.getBoolean(0));
+ assertEquals(true, list.setBoolean(0, false));
+ assertEquals(false, list.getBoolean(0));
- assertTrue(list.setBoolean(1, false));
- assertFalse(list.getBoolean(1));
+ assertEquals(true, list.setBoolean(1, false));
+ assertEquals(false, list.getBoolean(1));
try {
list.setBoolean(-1, false);
@@ -255,8 +255,8 @@
assertTrue(list.addAll(Collections.singleton(true)));
assertEquals(1, list.size());
- assertTrue(list.get(0));
- assertTrue(list.getBoolean(0));
+ assertEquals(true, (boolean) list.get(0));
+ assertEquals(true, list.getBoolean(0));
assertTrue(list.addAll(asList(false, true, false, true, false)));
assertEquals(asList(true, false, true, false, true, false), list);
@@ -268,9 +268,16 @@
assertFalse(list.addAll(BooleanArrayList.emptyList()));
}
+ public void testEquals() {
+ BooleanArrayList list1 = new BooleanArrayList();
+ BooleanArrayList list2 = new BooleanArrayList();
+
+ assertEquals(list1, list2);
+ }
+
public void testRemove() {
list.addAll(TERTIARY_LIST);
- assertTrue(list.remove(0));
+ assertEquals(true, (boolean) list.remove(0));
assertEquals(asList(false, true), list);
assertTrue(list.remove(Boolean.TRUE));
@@ -279,7 +286,7 @@
assertFalse(list.remove(Boolean.TRUE));
assertEquals(asList(false), list);
- assertFalse(list.remove(0));
+ assertEquals(false, (boolean) list.remove(0));
assertEquals(asList(), list);
try {
@@ -296,13 +303,22 @@
}
}
- public void testRemoveEndOfCapacity() {
+ public void testRemoveEnd_listAtCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
+ public void testRemove_listAtCapacity() {
+ BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(2);
+ toRemove.addBoolean(true);
+ toRemove.addBoolean(false);
+ toRemove.remove(0);
+ assertEquals(1, toRemove.size());
+ assertEquals(false, (boolean) toRemove.get(0));
+ }
+
public void testSublistRemoveEndOfCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true);
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index f64df33..998f4d5 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import static org.junit.Assert.assertArrayEquals;
import protobuf_unittest.UnittestProto.BoolMessage;
import protobuf_unittest.UnittestProto.Int32Message;
import protobuf_unittest.UnittestProto.Int64Message;
@@ -51,9 +52,9 @@
* @author kenton@google.com Kenton Varda
*/
public class CodedInputStreamTest extends TestCase {
-
- private static final int DEFAULT_BLOCK_SIZE = 4096;
-
+
+ private static final int DEFAULT_BLOCK_SIZE = 4096;
+
private enum InputType {
ARRAY {
@Override
@@ -88,10 +89,10 @@
if (blockSize > DEFAULT_BLOCK_SIZE) {
blockSize = DEFAULT_BLOCK_SIZE;
}
- ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+ ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
for (int i = 0; i < data.length; i += blockSize) {
- int rl = Math.min(blockSize, data.length - i);
- ByteBuffer rb = ByteBuffer.allocateDirect(rl);
+ int rl = Math.min(blockSize, data.length - i);
+ ByteBuffer rb = ByteBuffer.allocateDirect(rl);
rb.put(data, i, rl);
rb.flip();
input.add(rb);
@@ -105,10 +106,10 @@
if (blockSize > DEFAULT_BLOCK_SIZE) {
blockSize = DEFAULT_BLOCK_SIZE;
}
- ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+ ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
for (int i = 0; i < data.length; i += blockSize) {
- int rl = Math.min(blockSize, data.length - i);
- ByteBuffer rb = ByteBuffer.allocateDirect(rl);
+ int rl = Math.min(blockSize, data.length - i);
+ ByteBuffer rb = ByteBuffer.allocateDirect(rl);
rb.put(data, i, rl);
rb.flip();
input.add(rb);
@@ -116,8 +117,6 @@
return CodedInputStream.newInstance(new IterableByteBufferInputStream(input));
}
};
-
-
CodedInputStream newDecoder(byte[] data) {
return newDecoder(data, data.length);
@@ -144,6 +143,8 @@
*/
private static final class SmallBlockInputStream extends FilterInputStream {
private final int blockSize;
+ private int skipCalls;
+ private int readCalls;
public SmallBlockInputStream(byte[] data, int blockSize) {
super(new ByteArrayInputStream(data));
@@ -151,14 +152,28 @@
}
@Override
+ public int read() throws IOException {
+ readCalls++;
+ return super.read();
+ }
+
+ @Override
public int read(byte[] b) throws IOException {
+ readCalls++;
return super.read(b, 0, Math.min(b.length, blockSize));
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
+ readCalls++;
return super.read(b, off, Math.min(len, blockSize));
}
+
+ @Override
+ public long skip(long len) throws IOException {
+ skipCalls++;
+ return super.skip(Math.min(len, blockSize));
+ }
}
private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
@@ -430,6 +445,41 @@
}
}
+ /**
+ * Test that calling skipRawBytes (when not merging a message) actually skips from the underlying
+ * inputstream, regardless of the buffer size used.
+ */
+ public void testSkipRawBytesActuallySkips() throws Exception {
+ SmallBlockInputStream bytes = new SmallBlockInputStream(new byte[] {1, 2, 3, 4, 5}, 3);
+ CodedInputStream input = CodedInputStream.newInstance(bytes, 1); // Tiny buffer
+ input.skipRawBytes(3);
+ input.skipRawBytes(2);
+ assertEquals(2, bytes.skipCalls);
+ assertEquals(0, bytes.readCalls);
+ }
+
+ public void testSkipHugeBlob() throws Exception {
+ // Allocate and initialize a 1MB blob.
+ int blobSize = 1 << 20;
+ byte[] blob = new byte[blobSize];
+ for (int i = 0; i < blob.length; i++) {
+ blob[i] = (byte) i;
+ }
+
+ for (InputType inputType : InputType.values()) {
+ CodedInputStream decoder = inputType.newDecoder(blob);
+ decoder.skipRawBytes(blobSize - 10);
+ byte[] remaining = decoder.readRawBytes(10);
+ assertArrayEquals(Arrays.copyOfRange(blob, blobSize - 10, blobSize), remaining);
+ }
+ }
+
+ /** Skipping a huge blob should not allocate excessive memory, so there should be no limit */
+ public void testSkipMaliciouslyHugeBlob() throws Exception {
+ InputStream is = new RepeatingInputStream(new byte[]{1}, Integer.MAX_VALUE);
+ CodedInputStream.newInstance(is).skipRawBytes(Integer.MAX_VALUE);
+ }
+
public void testReadHugeBlob() throws Exception {
// Allocate and initialize a 1MB blob.
byte[] blob = new byte[1 << 20];
@@ -485,8 +535,9 @@
}
/**
- * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT
- * in size (2G or Integer#MAX_SIZE).
+ * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or
+ * Integer#MAX_SIZE).
+ *
* @throws IOException
*/
public void testParseMessagesCloseTo2G() throws IOException {
@@ -501,8 +552,9 @@
}
/**
- * Test there is an exception if a message exceeds
- * CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE).
+ * Test there is an exception if a message exceeds CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G
+ * or Integer#MAX_SIZE).
+ *
* @throws IOException
*/
public void testParseMessagesOver2G() throws IOException {
@@ -526,7 +578,7 @@
* @return A serialized big message.
*/
private static byte[] getBigSerializedMessage() {
- byte[] value = new byte[16 * 1024 * 1024];
+ byte[] value = new byte[16 * 1024 * 1024];
ByteString bsValue = ByteString.wrap(value);
return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArray();
}
@@ -654,7 +706,7 @@
checkSizeLimitExceeded(expected);
}
}
-
+
public void testRefillBufferWithCorrectSize() throws Exception {
// NOTE: refillBuffer only applies to the stream-backed CIS.
byte[] bytes = "123456789".getBytes("UTF-8");
@@ -672,14 +724,15 @@
output.flush();
// Input is two string with length 9 and one raw byte.
- byte[] rawInput = rawOutput.toByteArray();
- for (int inputStreamBufferLength = 8;
- inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) {
- CodedInputStream input = CodedInputStream.newInstance(
- new ByteArrayInputStream(rawInput), inputStreamBufferLength);
+ byte[] rawInput = rawOutput.toByteArray();
+ for (int inputStreamBufferLength = 8;
+ inputStreamBufferLength <= rawInput.length + 1;
+ inputStreamBufferLength++) {
+ CodedInputStream input =
+ CodedInputStream.newInstance(new ByteArrayInputStream(rawInput), inputStreamBufferLength);
input.setSizeLimit(rawInput.length - 1);
input.readString();
- input.readString();
+ input.readString();
try {
input.readRawByte(); // Hits limit.
fail("Should have thrown an exception!");
@@ -690,9 +743,8 @@
}
public void testIsAtEnd() throws Exception {
- CodedInputStream input = CodedInputStream.newInstance(
- new ByteArrayInputStream(new byte[5]));
- try {
+ CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(new byte[5]));
+ try {
for (int i = 0; i < 5; i++) {
assertEquals(false, input.isAtEnd());
input.readRawByte();
@@ -715,19 +767,18 @@
output.flush();
byte[] rawInput = rawOutput.toByteArray();
- CodedInputStream input = CodedInputStream.newInstance(
- new ByteArrayInputStream(rawInput));
+ CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(rawInput));
// The length of the whole rawInput
input.setSizeLimit(11);
// Some number that is smaller than the rawInput's length
- // but larger than 2
+ // but larger than 2
input.pushLimit(5);
try {
input.readString();
fail("Should have thrown an exception");
} catch (InvalidProtocolBufferException expected) {
- assertEquals(expected.getMessage(),
- InvalidProtocolBufferException.truncatedMessage().getMessage());
+ assertEquals(
+ expected.getMessage(), InvalidProtocolBufferException.truncatedMessage().getMessage());
}
}
@@ -936,13 +987,14 @@
output.flush();
byte[] data = rawOutput.toByteString().toByteArray();
- CodedInputStream input = CodedInputStream.newInstance(
- new ByteArrayInputStream(data) {
- @Override
- public synchronized int available() {
- return 0;
- }
- });
+ CodedInputStream input =
+ CodedInputStream.newInstance(
+ new ByteArrayInputStream(data) {
+ @Override
+ public synchronized int available() {
+ return 0;
+ }
+ });
ByteString result = input.readBytes();
assertEquals(ByteString.copyFrom(bytes), result);
}
@@ -959,13 +1011,14 @@
output.flush();
byte[] data = rawOutput.toByteString().toByteArray();
- CodedInputStream input = CodedInputStream.newInstance(
- new ByteArrayInputStream(data) {
- @Override
- public synchronized int available() {
- return 0;
- }
- });
+ CodedInputStream input =
+ CodedInputStream.newInstance(
+ new ByteArrayInputStream(data) {
+ @Override
+ public synchronized int available() {
+ return 0;
+ }
+ });
byte[] result = input.readByteArray();
assertTrue(Arrays.equals(bytes, result));
}
@@ -1034,8 +1087,8 @@
byte[] data = byteArrayStream.toByteArray();
for (InputType inputType : InputType.values()) {
- if (inputType == InputType.STREAM
- || inputType == InputType.STREAM_ITER_DIRECT
+ if (inputType == InputType.STREAM
+ || inputType == InputType.STREAM_ITER_DIRECT
|| inputType == InputType.ITER_DIRECT) {
// Aliasing doesn't apply to stream-backed CIS.
continue;
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index b60cd62..5f91324 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -79,8 +79,7 @@
private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
public void testFieldTypeEnumMapping() throws Exception {
- assertEquals(FieldDescriptor.Type.values().length,
- FieldDescriptorProto.Type.values().length);
+ assertEquals(FieldDescriptor.Type.values().length, FieldDescriptorProto.Type.values().length);
for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
FieldDescriptorProto.Type protoType = type.toProto();
assertEquals("TYPE_" + type.name(), protoType.name());
@@ -95,11 +94,9 @@
assertEquals("protobuf_unittest", file.getPackage());
assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
- assertEquals("google/protobuf/unittest.proto",
- file.toProto().getName());
+ assertEquals("google/protobuf/unittest.proto", file.toProto().getName());
- assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
- file.getDependencies());
+ assertEquals(Arrays.asList(UnittestImport.getDescriptor()), file.getDependencies());
Descriptor messageType = TestAllTypes.getDescriptor();
assertEquals(messageType, file.getMessageTypes().get(0));
@@ -115,9 +112,9 @@
assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
assertNull(file.findEnumTypeByName("NoSuchType"));
assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
- assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
- ImportEnumForMap.getDescriptor()),
- UnittestImport.getDescriptor().getEnumTypes());
+ assertEquals(
+ Arrays.asList(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()),
+ UnittestImport.getDescriptor().getEnumTypes());
for (int i = 0; i < file.getEnumTypes().size(); i++) {
assertEquals(i, file.getEnumTypes().get(i).getIndex());
}
@@ -127,22 +124,17 @@
assertEquals(service, file.findServiceByName("TestService"));
assertNull(file.findServiceByName("NoSuchType"));
assertNull(file.findServiceByName("protobuf_unittest.TestService"));
- assertEquals(Collections.emptyList(),
- UnittestImport.getDescriptor().getServices());
+ assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getServices());
for (int i = 0; i < file.getServices().size(); i++) {
assertEquals(i, file.getServices().get(i).getIndex());
}
- FieldDescriptor extension =
- UnittestProto.optionalInt32Extension.getDescriptor();
+ FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
assertEquals(extension, file.getExtensions().get(0));
- assertEquals(extension,
- file.findExtensionByName("optional_int32_extension"));
+ assertEquals(extension, file.findExtensionByName("optional_int32_extension"));
assertNull(file.findExtensionByName("no_such_ext"));
- assertNull(file.findExtensionByName(
- "protobuf_unittest.optional_int32_extension"));
- assertEquals(Collections.emptyList(),
- UnittestImport.getDescriptor().getExtensions());
+ assertNull(file.findExtensionByName("protobuf_unittest.optional_int32_extension"));
+ assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getExtensions());
for (int i = 0; i < file.getExtensions().size(); i++) {
assertEquals(i, file.getExtensions().get(i).getIndex());
}
@@ -156,13 +148,11 @@
assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
assertNull(messageType.getContainingType());
- assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
- messageType.getOptions());
+ assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), messageType.getOptions());
assertEquals("TestAllTypes", messageType.toProto().getName());
assertEquals("NestedMessage", nestedType.getName());
- assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
- nestedType.getFullName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(messageType, nestedType.getContainingType());
@@ -194,36 +184,28 @@
public void testFieldDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor();
- FieldDescriptor primitiveField =
- messageType.findFieldByName("optional_int32");
- FieldDescriptor enumField =
- messageType.findFieldByName("optional_nested_enum");
- FieldDescriptor messageField =
- messageType.findFieldByName("optional_foreign_message");
- FieldDescriptor cordField =
- messageType.findFieldByName("optional_cord");
- FieldDescriptor extension =
- UnittestProto.optionalInt32Extension.getDescriptor();
+ FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
+ FieldDescriptor enumField = messageType.findFieldByName("optional_nested_enum");
+ FieldDescriptor messageField = messageType.findFieldByName("optional_foreign_message");
+ FieldDescriptor cordField = messageType.findFieldByName("optional_cord");
+ FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
assertEquals("optional_int32", primitiveField.getName());
- assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
- primitiveField.getFullName());
+ assertEquals("protobuf_unittest.TestAllTypes.optional_int32", primitiveField.getFullName());
assertEquals(1, primitiveField.getNumber());
assertEquals(messageType, primitiveField.getContainingType());
assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
- assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
- primitiveField.getOptions());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), primitiveField.getOptions());
assertFalse(primitiveField.isExtension());
assertEquals("optional_int32", primitiveField.toProto().getName());
assertEquals("optional_nested_enum", enumField.getName());
assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
- assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
- enumField.getEnumType());
+ assertEquals(TestAllTypes.NestedEnum.getDescriptor(), enumField.getEnumType());
assertEquals("optional_foreign_message", messageField.getName());
assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
@@ -233,38 +215,29 @@
assertEquals("optional_cord", cordField.getName());
assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
- assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
- cordField.getOptions().getCtype());
+ assertEquals(DescriptorProtos.FieldOptions.CType.CORD, cordField.getOptions().getCtype());
assertEquals("optional_int32_extension", extension.getName());
- assertEquals("protobuf_unittest.optional_int32_extension",
- extension.getFullName());
+ assertEquals("protobuf_unittest.optional_int32_extension", extension.getFullName());
assertEquals(1, extension.getNumber());
- assertEquals(TestAllExtensions.getDescriptor(),
- extension.getContainingType());
+ assertEquals(TestAllExtensions.getDescriptor(), extension.getContainingType());
assertEquals(UnittestProto.getDescriptor(), extension.getFile());
assertEquals(FieldDescriptor.Type.INT32, extension.getType());
assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
- assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
- extension.getOptions());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), extension.getOptions());
assertTrue(extension.isExtension());
assertEquals(null, extension.getExtensionScope());
assertEquals("optional_int32_extension", extension.toProto().getName());
assertEquals("single", nestedExtension.getName());
- assertEquals("protobuf_unittest.TestRequired.single",
- nestedExtension.getFullName());
- assertEquals(TestRequired.getDescriptor(),
- nestedExtension.getExtensionScope());
+ assertEquals("protobuf_unittest.TestRequired.single", nestedExtension.getFullName());
+ assertEquals(TestRequired.getDescriptor(), nestedExtension.getExtensionScope());
}
public void testFieldDescriptorLabel() throws Exception {
- FieldDescriptor requiredField =
- TestRequired.getDescriptor().findFieldByName("a");
- FieldDescriptor optionalField =
- TestAllTypes.getDescriptor().findFieldByName("optional_int32");
- FieldDescriptor repeatedField =
- TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+ FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
+ FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+ FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
assertTrue(requiredField.isRequired());
assertFalse(requiredField.isRepeated());
@@ -273,7 +246,7 @@
assertFalse(repeatedField.isRequired());
assertTrue(repeatedField.isRepeated());
}
-
+
public void testFieldDescriptorJsonName() throws Exception {
FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
@@ -292,9 +265,8 @@
d = TestExtremeDefaultValues.getDescriptor();
assertEquals(
- ByteString.copyFrom(
- "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
- d.findFieldByName("escaped_bytes").getDefaultValue());
+ ByteString.copyFrom("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
+ d.findFieldByName("escaped_bytes").getDefaultValue());
assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
}
@@ -307,12 +279,10 @@
assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
assertNull(enumType.getContainingType());
- assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
- enumType.getOptions());
+ assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), enumType.getOptions());
assertEquals("NestedEnum", nestedType.getName());
- assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
- nestedType.getFullName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
@@ -339,18 +309,14 @@
MethodDescriptor fooMethod = service.getMethods().get(0);
assertEquals("Foo", fooMethod.getName());
- assertEquals(UnittestProto.FooRequest.getDescriptor(),
- fooMethod.getInputType());
- assertEquals(UnittestProto.FooResponse.getDescriptor(),
- fooMethod.getOutputType());
+ assertEquals(UnittestProto.FooRequest.getDescriptor(), fooMethod.getInputType());
+ assertEquals(UnittestProto.FooResponse.getDescriptor(), fooMethod.getOutputType());
assertEquals(fooMethod, service.findMethodByName("Foo"));
MethodDescriptor barMethod = service.getMethods().get(1);
assertEquals("Bar", barMethod.getName());
- assertEquals(UnittestProto.BarRequest.getDescriptor(),
- barMethod.getInputType());
- assertEquals(UnittestProto.BarResponse.getDescriptor(),
- barMethod.getOutputType());
+ assertEquals(UnittestProto.BarRequest.getDescriptor(), barMethod.getInputType());
+ assertEquals(UnittestProto.BarResponse.getDescriptor(), barMethod.getOutputType());
assertEquals(barMethod, service.findMethodByName("Bar"));
assertNull(service.findMethodByName("NoSuchMethod"));
@@ -367,58 +333,53 @@
// dependencies are also properly initialized.
Descriptor descriptor =
TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
- .findFieldByName("field").getMessageType();
+ .findFieldByName("field")
+ .getMessageType();
- assertTrue(
- descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
- assertEquals(Integer.valueOf(-56),
- descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+ assertTrue(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
+ assertEquals(
+ Integer.valueOf(-56),
+ descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
FieldDescriptor field = descriptor.findFieldByName("field1");
assertNotNull(field);
- assertTrue(
- field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
- assertEquals(Long.valueOf(8765432109L),
- field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+ assertTrue(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
+ assertEquals(
+ Long.valueOf(8765432109L),
+ field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
OneofDescriptor oneof = descriptor.getOneofs().get(0);
assertNotNull(oneof);
- assertTrue(
- oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
- assertEquals(Integer.valueOf(-99),
- oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
+ assertTrue(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
+ assertEquals(
+ Integer.valueOf(-99), oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
EnumDescriptor enumType =
- UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
+ UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
- assertTrue(
- enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
- assertEquals(Integer.valueOf(-789),
- enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+ assertTrue(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
+ assertEquals(
+ Integer.valueOf(-789), enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
- ServiceDescriptor service =
- UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
+ ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
- assertTrue(
- service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
- assertEquals(Long.valueOf(-9876543210L),
- service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+ assertTrue(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
+ assertEquals(
+ Long.valueOf(-9876543210L),
+ service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
MethodDescriptor method = service.findMethodByName("Foo");
assertNotNull(method);
- assertTrue(
- method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
- assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
- method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+ assertTrue(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
+ assertEquals(
+ UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
+ method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
}
- /**
- * Test that the FieldDescriptor.Type enum is the same as the
- * WireFormat.FieldType enum.
- */
+ /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
public void testFieldTypeTablesMatch() throws Exception {
FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
@@ -430,10 +391,7 @@
}
}
- /**
- * Test that the FieldDescriptor.JavaType enum is the same as the
- * WireFormat.JavaType enum.
- */
+ /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
public void testJavaTypeTablesMatch() throws Exception {
FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
@@ -448,31 +406,29 @@
public void testEnormousDescriptor() throws Exception {
// The descriptor for this file is larger than 64k, yet it did not cause
// a compiler error due to an over-long string literal.
- assertTrue(
- UnittestEnormousDescriptor.getDescriptor()
- .toProto().getSerializedSize() > 65536);
+ assertTrue(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize() > 65536);
}
- /**
- * Tests that the DescriptorValidationException works as intended.
- */
+ /** Tests that the DescriptorValidationException works as intended. */
public void testDescriptorValidatorException() throws Exception {
- FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setType(FieldDescriptorProto.Type.TYPE_INT32)
- .setName("foo")
- .setNumber(1)
- .setDefaultValue("invalid")
- .build())
- .build())
- .build();
+ FileDescriptorProto fileDescriptorProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setType(FieldDescriptorProto.Type.TYPE_INT32)
+ .setName("foo")
+ .setNumber(1)
+ .setDefaultValue("invalid")
+ .build())
+ .build())
+ .build();
try {
- Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
- new FileDescriptor[0]);
+ Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
// Expected; check that the error message contains some useful hints
@@ -485,35 +441,39 @@
}
/**
- * Tests the translate/crosslink for an example where a message field's name
- * and type name are the same.
+ * Tests the translate/crosslink for an example where a message field's name and type name are the
+ * same.
*/
public void testDescriptorComplexCrosslink() throws Exception {
- FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setType(FieldDescriptorProto.Type.TYPE_INT32)
- .setName("foo")
- .setNumber(1)
- .build())
- .build())
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Bar")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setTypeName("Foo")
- .setName("Foo")
- .setNumber(1)
- .build())
- .build())
- .build();
+ FileDescriptorProto fileDescriptorProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setType(FieldDescriptorProto.Type.TYPE_INT32)
+ .setName("foo")
+ .setNumber(1)
+ .build())
+ .build())
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Bar")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Foo")
+ .setName("Foo")
+ .setNumber(1)
+ .build())
+ .build())
+ .build();
// translate and crosslink
FileDescriptor file =
- Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
- new FileDescriptor[0]);
+ Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
// verify resulting descriptors
assertNotNull(file);
List<Descriptor> msglist = file.getMessageTypes();
@@ -535,62 +495,57 @@
}
public void testDependencyOrder() throws Exception {
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto").build();
- FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
- .setName("bar.proto")
- .addDependency("foo.proto")
- .build();
- FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
- .setName("baz.proto")
- .addDependency("foo.proto")
- .addDependency("bar.proto")
- .addPublicDependency(0)
- .addPublicDependency(1)
- .build();
- FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
- new FileDescriptor[0]);
- FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
- new FileDescriptor[] {fooFile});
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
+ FileDescriptorProto barProto =
+ FileDescriptorProto.newBuilder().setName("bar.proto").addDependency("foo.proto").build();
+ FileDescriptorProto bazProto =
+ FileDescriptorProto.newBuilder()
+ .setName("baz.proto")
+ .addDependency("foo.proto")
+ .addDependency("bar.proto")
+ .addPublicDependency(0)
+ .addPublicDependency(1)
+ .build();
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+ FileDescriptor barFile =
+ Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
// Items in the FileDescriptor array can be in any order.
- Descriptors.FileDescriptor.buildFrom(bazProto,
- new FileDescriptor[] {fooFile, barFile});
- Descriptors.FileDescriptor.buildFrom(bazProto,
- new FileDescriptor[] {barFile, fooFile});
+ Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile});
+ Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
}
public void testInvalidPublicDependency() throws Exception {
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto").build();
- FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
- .setName("boo.proto")
- .addDependency("foo.proto")
- .addPublicDependency(1) // Error, should be 0.
- .build();
- FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
- new FileDescriptor[0]);
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
+ FileDescriptorProto barProto =
+ FileDescriptorProto.newBuilder()
+ .setName("boo.proto")
+ .addDependency("foo.proto")
+ .addPublicDependency(1) // Error, should be 0.
+ .build();
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
try {
- Descriptors.FileDescriptor.buildFrom(barProto,
- new FileDescriptor[] {fooFile});
+ Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
- assertTrue(
- e.getMessage().indexOf("Invalid public dependency index.") != -1);
+ assertTrue(e.getMessage().indexOf("Invalid public dependency index.") != -1);
}
}
public void testUnknownFieldsDenied() throws Exception {
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setTypeName("Bar")
- .setName("bar")
- .setNumber(1)))
- .build();
+ FileDescriptorProto fooProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
try {
Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
@@ -602,48 +557,54 @@
}
public void testUnknownFieldsAllowed() throws Exception {
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addDependency("bar.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setTypeName("Bar")
- .setName("bar")
- .setNumber(1)))
- .build();
+ FileDescriptorProto fooProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("bar.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
}
public void testHiddenDependency() throws Exception {
- FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
- .setName("bar.proto")
- .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
- .build();
- FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
- .setName("forward.proto")
- .addDependency("bar.proto")
- .build();
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addDependency("forward.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setTypeName("Bar")
- .setName("bar")
- .setNumber(1)))
- .build();
- FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
- barProto, new FileDescriptor[0]);
- FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
- forwardProto, new FileDescriptor[] {barFile});
+ FileDescriptorProto barProto =
+ FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+ .build();
+ FileDescriptorProto forwardProto =
+ FileDescriptorProto.newBuilder()
+ .setName("forward.proto")
+ .addDependency("bar.proto")
+ .build();
+ FileDescriptorProto fooProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("forward.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
+ FileDescriptor forwardFile =
+ Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
try {
- Descriptors.FileDescriptor.buildFrom(
- fooProto, new FileDescriptor[] {forwardFile});
+ Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
assertTrue(e.getMessage().indexOf("Bar") != -1);
@@ -652,65 +613,67 @@
}
public void testPublicDependency() throws Exception {
- FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
- .setName("bar.proto")
- .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
- .build();
- FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
- .setName("forward.proto")
- .addDependency("bar.proto")
- .addPublicDependency(0)
- .build();
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addDependency("forward.proto")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Foo")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
- .setTypeName("Bar")
- .setName("bar")
- .setNumber(1)))
- .build();
- FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
- barProto, new FileDescriptor[0]);
- FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
- forwardProto, new FileDescriptor[]{barFile});
- Descriptors.FileDescriptor.buildFrom(
- fooProto, new FileDescriptor[] {forwardFile});
+ FileDescriptorProto barProto =
+ FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+ .build();
+ FileDescriptorProto forwardProto =
+ FileDescriptorProto.newBuilder()
+ .setName("forward.proto")
+ .addDependency("bar.proto")
+ .addPublicDependency(0)
+ .build();
+ FileDescriptorProto fooProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("forward.proto")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+ FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
+ FileDescriptor forwardFile =
+ Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
+ Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
}
- /**
- * Tests the translate/crosslink for an example with a more complex namespace
- * referencing.
- */
+ /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
public void testComplexNamespacePublicDependency() throws Exception {
- FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
- .setName("bar.proto")
- .setPackage("a.b.c.d.bar.shared")
- .addEnumType(EnumDescriptorProto.newBuilder()
- .setName("MyEnum")
- .addValue(EnumValueDescriptorProto.newBuilder()
- .setName("BLAH")
- .setNumber(1)))
- .build();
- FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addDependency("bar.proto")
- .setPackage("a.b.c.d.foo.shared")
- .addMessageType(DescriptorProto.newBuilder()
- .setName("MyMessage")
- .addField(FieldDescriptorProto.newBuilder()
- .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
- .setTypeName("bar.shared.MyEnum")
- .setName("MyField")
- .setNumber(1)))
- .build();
+ FileDescriptorProto fooProto =
+ FileDescriptorProto.newBuilder()
+ .setName("bar.proto")
+ .setPackage("a.b.c.d.bar.shared")
+ .addEnumType(
+ EnumDescriptorProto.newBuilder()
+ .setName("MyEnum")
+ .addValue(EnumValueDescriptorProto.newBuilder().setName("BLAH").setNumber(1)))
+ .build();
+ FileDescriptorProto barProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("bar.proto")
+ .setPackage("a.b.c.d.foo.shared")
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("MyMessage")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+ .setTypeName("bar.shared.MyEnum")
+ .setName("MyField")
+ .setNumber(1)))
+ .build();
// translate and crosslink
- FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
- fooProto, new FileDescriptor[0]);
- FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
- barProto, new FileDescriptor[]{fooFile});
+ FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+ FileDescriptor barFile =
+ Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
// verify resulting descriptors
assertNotNull(barFile);
List<Descriptor> msglist = barFile.getMessageTypes();
@@ -726,15 +689,13 @@
assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
assertTrue(field.getEnumType().getName().equals("MyEnum"));
assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
- assertTrue(field.getEnumType().getFile().getPackage().equals(
- "a.b.c.d.bar.shared"));
+ assertTrue(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"));
}
}
public void testOneofDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor();
- FieldDescriptor field =
- messageType.findFieldByName("oneof_nested_message");
+ FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
OneofDescriptor oneofDescriptor = field.getContainingOneof();
assertNotNull(oneofDescriptor);
assertSame(oneofDescriptor, messageType.getOneofs().get(0));
@@ -774,36 +735,38 @@
}
public void testToString() {
- assertEquals("protobuf_unittest.TestAllTypes.optional_uint64",
- UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber(
- UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString());
+ assertEquals(
+ "protobuf_unittest.TestAllTypes.optional_uint64",
+ UnittestProto.TestAllTypes.getDescriptor()
+ .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
+ .toString());
}
public void testPackedEnumField() throws Exception {
- FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
- .setName("foo.proto")
- .addEnumType(EnumDescriptorProto.newBuilder()
- .setName("Enum")
- .addValue(EnumValueDescriptorProto.newBuilder()
- .setName("FOO")
- .setNumber(1)
- .build())
- .build())
- .addMessageType(DescriptorProto.newBuilder()
- .setName("Message")
- .addField(FieldDescriptorProto.newBuilder()
- .setName("foo")
- .setTypeName("Enum")
- .setNumber(1)
- .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
- .setOptions(DescriptorProtos.FieldOptions.newBuilder()
- .setPacked(true)
- .build())
- .build())
- .build())
- .build();
- Descriptors.FileDescriptor.buildFrom(
- fileDescriptorProto, new FileDescriptor[0]);
+ FileDescriptorProto fileDescriptorProto =
+ FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addEnumType(
+ EnumDescriptorProto.newBuilder()
+ .setName("Enum")
+ .addValue(
+ EnumValueDescriptorProto.newBuilder().setName("FOO").setNumber(1).build())
+ .build())
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("Message")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("foo")
+ .setTypeName("Enum")
+ .setNumber(1)
+ .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+ .setOptions(
+ DescriptorProtos.FieldOptions.newBuilder().setPacked(true).build())
+ .build())
+ .build())
+ .build();
+ Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
}
public void testFieldJsonName() throws Exception {
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index 6a94212..3a8254a 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -266,6 +266,15 @@
assertFalse(list.addAll(DoubleArrayList.emptyList()));
}
+ public void testEquals() {
+ DoubleArrayList list1 = new DoubleArrayList();
+ DoubleArrayList list2 = new DoubleArrayList();
+
+ list1.addDouble(Double.longBitsToDouble(0x7ff0000000000001L));
+ list2.addDouble(Double.longBitsToDouble(0x7ff0000000000002L));
+ assertEquals(list1, list2);
+ }
+
public void testRemove() {
list.addAll(TERTIARY_LIST);
assertEquals(1D, (double) list.remove(0), 0.0);
@@ -294,13 +303,22 @@
}
}
- public void testRemoveEndOfCapacity() {
+ public void testRemoveEnd_listAtCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
+ public void testRemove_listAtCapacity() {
+ DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(2);
+ toRemove.addDouble(3);
+ toRemove.addDouble(4);
+ toRemove.remove(0);
+ assertEquals(1, toRemove.size());
+ assertEquals(4D, (double) toRemove.get(0));
+ }
+
public void testSublistRemoveEndOfCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3);
diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
index a0e9137..d1e4a29 100644
--- a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -238,7 +238,7 @@
classLoader.loadClass(ExtensionRegistryFactory.class.getName());
Class<?> test = classLoader.loadClass(testClass.getName());
String testName = getName();
- test.getMethod(testName).invoke(test.newInstance());
+ test.getMethod(testName).invoke(test.getDeclaredConstructor().newInstance());
}
/**
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index 7ed6134..77a2839 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -266,6 +266,15 @@
assertFalse(list.addAll(FloatArrayList.emptyList()));
}
+ public void testEquals() {
+ FloatArrayList list1 = new FloatArrayList();
+ FloatArrayList list2 = new FloatArrayList();
+
+ list1.addFloat(Float.intBitsToFloat(0xff800001));
+ list2.addFloat(Float.intBitsToFloat(0xff800002));
+ assertEquals(list1, list2);
+ }
+
public void testRemove() {
list.addAll(TERTIARY_LIST);
assertEquals(1F, (float) list.remove(0), 0.0f);
@@ -294,13 +303,22 @@
}
}
- public void testRemoveEndOfCapacity() {
+ public void testRemoveEnd_listAtCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
+ public void testRemove_listAtCapacity() {
+ FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(2);
+ toRemove.addFloat(3);
+ toRemove.addFloat(4);
+ toRemove.remove(0);
+ assertEquals(1, toRemove.size());
+ assertEquals(4F, (float) toRemove.get(0));
+ }
+
public void testSublistRemoveEndOfCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3);
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index d6943e0..51ebc98 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -266,6 +266,13 @@
assertFalse(list.addAll(IntArrayList.emptyList()));
}
+ public void testEquals() {
+ IntArrayList list1 = new IntArrayList();
+ IntArrayList list2 = new IntArrayList();
+
+ assertEquals(list1, list2);
+ }
+
public void testRemove() {
list.addAll(TERTIARY_LIST);
assertEquals(1, (int) list.remove(0));
@@ -294,13 +301,22 @@
}
}
- public void testRemoveEndOfCapacity() {
+ public void testRemoveEnd_listAtCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
+ public void testRemove_listAtCapacity() {
+ IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(2);
+ toRemove.addInt(3);
+ toRemove.addInt(4);
+ toRemove.remove(0);
+ assertEquals(1, toRemove.size());
+ assertEquals(4, (int) toRemove.get(0));
+ }
+
public void testSublistRemoveEndOfCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3);
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
index 2518f20..6a737f1 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -168,7 +168,7 @@
// A sanity check.
int actual = 0;
for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
- actual += shard.expected;
+ actual = (int) (actual + shard.expected);
}
assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
}
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
index 2c086e1..67d2f59 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -218,9 +218,9 @@
private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
assertEquals(numShards, expected.length);
List<Shard> shards = new ArrayList<Shard>(numShards);
- long LIM = 1L << 32;
- long increment = LIM / numShards;
- assertTrue(LIM % numShards == 0);
+ long lim = 1L << 32;
+ long increment = lim / numShards;
+ assertTrue(lim % numShards == 0);
for (int i = 0; i < numShards; i++) {
shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
index 813fe6b..8c13aca 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -117,8 +117,8 @@
LazyFieldLite original = createLazyFieldLiteFromMessage(message);
LazyFieldLite merged = new LazyFieldLite();
merged.merge(original);
- TestAllExtensions value = (TestAllExtensions) merged.getValue(
- TestAllExtensions.getDefaultInstance());
+ TestAllExtensions value =
+ (TestAllExtensions) merged.getValue(TestAllExtensions.getDefaultInstance());
assertEquals(message, value);
}
@@ -130,8 +130,8 @@
public void testInvalidProto() throws Exception {
// Silently fails and uses the default instance.
- LazyFieldLite field = new LazyFieldLite(
- TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+ LazyFieldLite field =
+ new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
assertEquals(
TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
assertEquals(0, field.getSerializedSize());
@@ -158,7 +158,7 @@
TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
LazyFieldLite field1 = LazyFieldLite.fromValue(message1);
- field1.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
+ field1.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
field1.merge(field2);
assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
@@ -166,7 +166,7 @@
// Now reverse which one is parsed first.
field1 = LazyFieldLite.fromValue(message1);
field2 = createLazyFieldLiteFromMessage(message2);
- field2.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
+ field2.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
field1.merge(field2);
assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
}
@@ -175,8 +175,8 @@
// Test a few different paths that involve one message that was not parsed.
TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
LazyFieldLite valid = LazyFieldLite.fromValue(message);
- LazyFieldLite invalid = new LazyFieldLite(
- TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+ LazyFieldLite invalid =
+ new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
invalid.merge(valid);
// We swallow the exception and just use the set field.
@@ -206,13 +206,13 @@
// Now try parsing the empty field first.
field = LazyFieldLite.fromValue(messageWithExtensions);
LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
- other.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
+ other.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
field.merge(other);
assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
// And again reverse.
field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
- field.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
+ field.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
other = LazyFieldLite.fromValue(messageWithExtensions);
field.merge(other);
assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
@@ -239,8 +239,7 @@
}
private void assertNotEqual(Object unexpected, Object actual) {
- assertFalse(unexpected == actual
- || (unexpected != null && unexpected.equals(actual)));
+ assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
}
}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index b20114e..89213a7 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -81,7 +81,7 @@
//
// We put this in setUp() rather than in its own test method because we
// need to make sure it runs before any actual tests.
- assertTrue(TestNestedExtensionLite.nestedExtension != null);
+ assertNotNull(TestNestedExtensionLite.nestedExtension);
}
public void testLite() throws Exception {
@@ -320,16 +320,16 @@
assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
message = builder.build();
- ForeignMessageLite.Builder foreignMessageBuilder = ForeignMessageLite.newBuilder().setC(3);
- builder.setOptionalForeignMessage(foreignMessageBuilder);
+ ForeignMessageLite foreignMessageC3 = ForeignMessageLite.newBuilder().setC(3).build();
+ builder.setOptionalForeignMessage(foreignMessageC3);
assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
- assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
+ assertEquals(foreignMessageC3, builder.getOptionalForeignMessage());
messageAfterBuild = builder.build();
- assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+ assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
builder.clearOptionalForeignMessage();
assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
- assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+ assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
message = builder.build();
OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
@@ -1033,11 +1033,11 @@
builder.clearRepeatedForeignMessage();
message = builder.build();
- builder.addRepeatedForeignMessage(foreignMessageBuilder);
+ builder.addRepeatedForeignMessage(foreignMessageC3);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount());
builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
- assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
+ assertEquals(foreignMessageC3, messageAfterBuild.getRepeatedForeignMessage(0));
assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
@@ -1045,9 +1045,9 @@
builder.addRepeatedForeignMessage(0, foreignMessage);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount());
- builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
+ builder.setRepeatedForeignMessage(0, foreignMessageC3);
assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
- assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
+ assertEquals(foreignMessageC3, builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
message = builder.build();
@@ -1533,7 +1533,7 @@
private static void assertToStringEquals(String expected, MessageLite message) {
String toString = message.toString();
assertEquals('#', toString.charAt(0));
- if (toString.indexOf("\n") >= 0) {
+ if (toString.contains("\n")) {
toString = toString.substring(toString.indexOf("\n") + 1);
} else {
toString = "";
@@ -2210,29 +2210,29 @@
public void testAddAllIteratesOnce() {
TestAllTypesLite.newBuilder()
- .addAllRepeatedBool(new OneTimeIterableList(false))
- .addAllRepeatedInt32(new OneTimeIterableList(0))
- .addAllRepeatedInt64(new OneTimeIterableList(0L))
- .addAllRepeatedFloat(new OneTimeIterableList(0f))
- .addAllRepeatedDouble(new OneTimeIterableList(0d))
- .addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY))
- .addAllRepeatedString(new OneTimeIterableList(""))
- .addAllRepeatedNestedMessage(new OneTimeIterableList(NestedMessage.getDefaultInstance()))
- .addAllRepeatedBool(new OneTimeIterable(false))
- .addAllRepeatedInt32(new OneTimeIterable(0))
- .addAllRepeatedInt64(new OneTimeIterable(0L))
- .addAllRepeatedFloat(new OneTimeIterable(0f))
- .addAllRepeatedDouble(new OneTimeIterable(0d))
- .addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY))
- .addAllRepeatedString(new OneTimeIterable(""))
- .addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance()))
+ .addAllRepeatedBool(new OneTimeIterableList<>(false))
+ .addAllRepeatedInt32(new OneTimeIterableList<>(0))
+ .addAllRepeatedInt64(new OneTimeIterableList<>(0L))
+ .addAllRepeatedFloat(new OneTimeIterableList<>(0f))
+ .addAllRepeatedDouble(new OneTimeIterableList<>(0d))
+ .addAllRepeatedBytes(new OneTimeIterableList<>(ByteString.EMPTY))
+ .addAllRepeatedString(new OneTimeIterableList<>(""))
+ .addAllRepeatedNestedMessage(new OneTimeIterableList<>(NestedMessage.getDefaultInstance()))
+ .addAllRepeatedBool(new OneTimeIterable<>(false))
+ .addAllRepeatedInt32(new OneTimeIterable<>(0))
+ .addAllRepeatedInt64(new OneTimeIterable<>(0L))
+ .addAllRepeatedFloat(new OneTimeIterable<>(0f))
+ .addAllRepeatedDouble(new OneTimeIterable<>(0d))
+ .addAllRepeatedBytes(new OneTimeIterable<>(ByteString.EMPTY))
+ .addAllRepeatedString(new OneTimeIterable<>(""))
+ .addAllRepeatedNestedMessage(new OneTimeIterable<>(NestedMessage.getDefaultInstance()))
.build();
}
public void testAddAllIteratesOnce_throwsOnNull() {
TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
try {
- builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null));
+ builder.addAllRepeatedBool(new OneTimeIterableList<>(true, false, null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2240,7 +2240,7 @@
}
try {
- builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null));
+ builder.addAllRepeatedBool(new OneTimeIterable<>(true, false, null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2249,7 +2249,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null));
+ builder.addAllRepeatedBool(new OneTimeIterableList<>((Boolean) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2258,7 +2258,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null));
+ builder.addAllRepeatedInt32(new OneTimeIterableList<>((Integer) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2267,7 +2267,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null));
+ builder.addAllRepeatedInt64(new OneTimeIterableList<>((Long) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2276,7 +2276,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null));
+ builder.addAllRepeatedFloat(new OneTimeIterableList<>((Float) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2285,7 +2285,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null));
+ builder.addAllRepeatedDouble(new OneTimeIterableList<>((Double) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2294,7 +2294,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null));
+ builder.addAllRepeatedBytes(new OneTimeIterableList<>((ByteString) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2303,7 +2303,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, ""));
+ builder.addAllRepeatedString(new OneTimeIterableList<>("", "", null, ""));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2312,7 +2312,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, ""));
+ builder.addAllRepeatedString(new OneTimeIterable<>("", "", null, ""));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2321,7 +2321,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedString(new OneTimeIterableList((String) null));
+ builder.addAllRepeatedString(new OneTimeIterableList<>((String) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2330,7 +2330,7 @@
try {
builder = TestAllTypesLite.newBuilder();
- builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null));
+ builder.addAllRepeatedNestedMessage(new OneTimeIterableList<>((NestedMessage) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 9e5adb7..0131ea2 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -369,13 +369,13 @@
}
@Override
- public void writeLazy(byte[] value, int offset, int length) throws IOException {
- Arrays.fill(value, offset, offset + length, (byte) 0);
+ public void write(ByteBuffer value) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- public void write(ByteBuffer value) throws IOException {
- throw new UnsupportedOperationException();
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ Arrays.fill(value, offset, offset + length, (byte) 0);
}
@Override
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index 4b5e6c7..1935100 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -266,6 +266,13 @@
assertFalse(list.addAll(LongArrayList.emptyList()));
}
+ public void testEquals() {
+ LongArrayList list1 = new LongArrayList();
+ LongArrayList list2 = new LongArrayList();
+
+ assertEquals(list1, list2);
+ }
+
public void testRemove() {
list.addAll(TERTIARY_LIST);
assertEquals(1L, (long) list.remove(0));
@@ -294,13 +301,22 @@
}
}
- public void testRemoveEndOfCapacity() {
+ public void testRemoveEnd_listAtCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
+ public void testRemove_listAtCapacity() {
+ LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(2);
+ toRemove.addLong(3);
+ toRemove.addLong(4);
+ toRemove.remove(0);
+ assertEquals(1, toRemove.size());
+ assertEquals(4L, (long) toRemove.get(0));
+ }
+
public void testSublistRemoveEndOfCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3);
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index 41fef07..adca1d5 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -440,12 +440,12 @@
// We can't control the order of elements in a HashMap. The best we can do
// here is to add elements in different order.
- TestMap.Builder b1 =
+ TestMap m1 =
TestMap.newBuilder()
.putInt32ToInt32Field(1, 2)
.putInt32ToInt32Field(3, 4)
- .putInt32ToInt32Field(5, 6);
- TestMap m1 = b1.build();
+ .putInt32ToInt32Field(5, 6)
+ .build();
TestMap.Builder b2 =
TestMap.newBuilder()
@@ -466,9 +466,12 @@
}
public void testUnknownEnumValues() throws Exception {
- TestUnknownEnumValue.Builder builder =
- TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
- ByteString data = builder.build().toByteString();
+ ByteString data =
+ TestUnknownEnumValue.newBuilder()
+ .putInt32ToInt32Field(1, 1)
+ .putInt32ToInt32Field(2, 54321)
+ .build()
+ .toByteString();
TestMap message = TestMap.parseFrom(data);
// Entries with unknown enum values will be stored into UnknownFieldSet so
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
index bcfd927..4961042 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -49,9 +49,7 @@
import java.util.Map;
import junit.framework.TestCase;
-/**
- * Unit tests for map fields in proto2 protos.
- */
+/** Unit tests for map fields in proto2 protos. */
public class MapForProto2Test extends TestCase {
private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
@@ -88,23 +86,18 @@
.putInt32ToInt32Field(1, 11)
.putInt32ToInt32Field(2, 22)
.putInt32ToInt32Field(3, 33)
-
.putInt32ToStringField(1, "11")
.putInt32ToStringField(2, "22")
.putInt32ToStringField(3, "33")
-
.putInt32ToBytesField(1, TestUtil.toBytes("11"))
.putInt32ToBytesField(2, TestUtil.toBytes("22"))
.putInt32ToBytesField(3, TestUtil.toBytes("33"))
-
.putInt32ToEnumField(1, TestMap.EnumValue.FOO)
.putInt32ToEnumField(2, TestMap.EnumValue.BAR)
.putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
-
.putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
.putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
.putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
-
.putStringToInt32Field("1", 11)
.putStringToInt32Field("2", 22)
.putStringToInt32Field("3", 33);
@@ -199,23 +192,18 @@
.putInt32ToInt32Field(1, 111)
.removeInt32ToInt32Field(2)
.putInt32ToInt32Field(4, 44)
-
.putInt32ToStringField(1, "111")
.removeInt32ToStringField(2)
.putInt32ToStringField(4, "44")
-
.putInt32ToBytesField(1, TestUtil.toBytes("111"))
.removeInt32ToBytesField(2)
.putInt32ToBytesField(4, TestUtil.toBytes("44"))
-
.putInt32ToEnumField(1, TestMap.EnumValue.BAR)
.removeInt32ToEnumField(2)
.putInt32ToEnumField(4, TestMap.EnumValue.QUX)
-
.putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
.removeInt32ToMessageField(2)
.putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
-
.putStringToInt32Field("1", 111)
.removeStringToInt32Field("2")
.putStringToInt32Field("4", 44);
@@ -337,7 +325,7 @@
assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
builder.getMutableInt32ToInt32Field().put(2, 3);
assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
- //
+ //
Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
enumMap.put(1, TestMap.EnumValue.BAR);
assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -432,7 +420,19 @@
assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
}
-
+ //
+ private static <K, V> Map<K, V> newMap(K key1, V value1) {
+ Map<K, V> map = new HashMap<K, V>();
+ map.put(key1, value1);
+ return map;
+ }
+ //
+ private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+ Map<K, V> map = new HashMap<K, V>();
+ map.put(key1, value1);
+ map.put(key2, value2);
+ return map;
+ }
public void testGettersAndSetters() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
@@ -543,30 +543,22 @@
ByteString bytes = TestUtil.toBytes("SOME BYTES");
String stringKey = "a string key";
- TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
- .putInt32ToInt32Field(5, bytes)
- .build());
+ TestMap map =
+ tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
- map = tryParseTestMap(BizarroTestMap.newBuilder()
- .putInt32ToStringField(stringKey, 5)
- .build());
+ map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
- map = tryParseTestMap(BizarroTestMap.newBuilder()
- .putInt32ToBytesField(stringKey, 5)
- .build());
+ map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
- map = tryParseTestMap(BizarroTestMap.newBuilder()
- .putInt32ToEnumField(stringKey, bytes)
- .build());
+ map =
+ tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try {
- tryParseTestMap(BizarroTestMap.newBuilder()
- .putInt32ToMessageField(stringKey, bytes)
- .build());
+ tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
fail();
} catch (InvalidProtocolBufferException expected) {
assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
@@ -574,9 +566,9 @@
assertTrue(map.getInt32ToMessageField().isEmpty());
}
- map = tryParseTestMap(BizarroTestMap.newBuilder()
- .putStringToInt32Field(stringKey, bytes)
- .build());
+ map =
+ tryParseTestMap(
+ BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
}
@@ -657,8 +649,7 @@
}
}
- private static <KeyType, ValueType>
- Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
+ private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) {
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
Message.Builder entryBuilder = builder.newBuilderForField(field);
FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
@@ -677,9 +668,8 @@
builder.setField(field, entryList);
}
- private static <KeyType, ValueType> Map<KeyType, ValueType> mapForValues(
- KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
- Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+ private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
+ Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);
map.put(key2, value2);
return map;
@@ -687,17 +677,19 @@
public void testReflectionApi() throws Exception {
// In reflection API, map fields are just repeated message fields.
- TestMap.Builder builder = TestMap.newBuilder()
- .putInt32ToInt32Field(1, 2)
- .putInt32ToInt32Field(3, 4)
- .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
- .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
+ TestMap.Builder builder =
+ TestMap.newBuilder()
+ .putInt32ToInt32Field(1, 2)
+ .putInt32ToInt32Field(3, 4)
+ .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+ .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
TestMap message = builder.build();
// Test getField(), getRepeatedFieldCount(), getRepeatedField().
- assertHasMapValues(message, "int32_to_int32_field",
- mapForValues(1, 2, 3, 4));
- assertHasMapValues(message, "int32_to_message_field",
+ assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4));
+ assertHasMapValues(
+ message,
+ "int32_to_message_field",
mapForValues(
11, MessageValue.newBuilder().setValue(22).build(),
33, MessageValue.newBuilder().setValue(44).build()));
@@ -710,9 +702,10 @@
assertEquals(0, message.getInt32ToMessageField().size());
// Test setField()
- setMapValues(builder, "int32_to_int32_field",
- mapForValues(11, 22, 33, 44));
- setMapValues(builder, "int32_to_message_field",
+ setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
+ setMapValues(
+ builder,
+ "int32_to_message_field",
mapForValues(
111, MessageValue.newBuilder().setValue(222).build(),
333, MessageValue.newBuilder().setValue(444).build()));
@@ -723,20 +716,28 @@
assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
// Test addRepeatedField
- builder.addRepeatedField(f("int32_to_int32_field"),
- newMapEntry(builder, "int32_to_int32_field", 55, 66));
- builder.addRepeatedField(f("int32_to_message_field"),
- newMapEntry(builder, "int32_to_message_field", 555,
+ builder.addRepeatedField(
+ f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66));
+ builder.addRepeatedField(
+ f("int32_to_message_field"),
+ newMapEntry(
+ builder,
+ "int32_to_message_field",
+ 555,
MessageValue.newBuilder().setValue(666).build()));
message = builder.build();
assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
// Test addRepeatedField (overriding existing values)
- builder.addRepeatedField(f("int32_to_int32_field"),
- newMapEntry(builder, "int32_to_int32_field", 55, 55));
- builder.addRepeatedField(f("int32_to_message_field"),
- newMapEntry(builder, "int32_to_message_field", 555,
+ builder.addRepeatedField(
+ f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55));
+ builder.addRepeatedField(
+ f("int32_to_message_field"),
+ newMapEntry(
+ builder,
+ "int32_to_message_field",
+ 555,
MessageValue.newBuilder().setValue(555).build()));
message = builder.build();
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
@@ -779,10 +780,9 @@
setMapValuesUsingAccessors(builder);
TestMap message = builder.build();
- Message dynamicDefaultInstance =
- DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
- Message dynamicMessage = dynamicDefaultInstance
- .newBuilderForType().mergeFrom(message.toByteString()).build();
+ Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+ Message dynamicMessage =
+ dynamicDefaultInstance.newBuilderForType().mergeFrom(message.toByteString()).build();
assertEquals(message, dynamicMessage);
assertEquals(message.hashCode(), dynamicMessage.hashCode());
@@ -793,8 +793,7 @@
public void testDynamicMessageUnsetKeyAndValue() throws Exception {
FieldDescriptor field = f("int32_to_int32_field");
- Message dynamicDefaultInstance =
- DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+ Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
// Add an entry without key and value.
builder.addRepeatedField(field, builder.newBuilderForField(field).build());
@@ -811,8 +810,7 @@
// of map entries when comparing/hashing map fields.
// We use DynamicMessage to test reflection based equals()/hashCode().
- Message dynamicDefaultInstance =
- DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+ Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
FieldDescriptor field = f("int32_to_int32_field");
Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
@@ -839,9 +837,8 @@
}
public void testUnknownEnumValues() throws Exception {
- TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
- .putInt32ToInt32Field(1, 1)
- .putInt32ToInt32Field(2, 54321);
+ TestUnknownEnumValue.Builder builder =
+ TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
ByteString data = builder.build().toByteString();
TestMap message = TestMap.parseFrom(data);
@@ -853,8 +850,7 @@
assertFalse(message.getUnknownFields().asMap().isEmpty());
// Serializing and parsing should preserve the unknown entry.
data = message.toByteString();
- TestUnknownEnumValue messageWithUnknownEnums =
- TestUnknownEnumValue.parseFrom(data);
+ TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
@@ -887,7 +883,8 @@
setMapValuesUsingAccessors(builder);
TestMap message = builder.build();
- assertEquals(Arrays.asList("1", "2", "3"),
+ assertEquals(
+ Arrays.asList("1", "2", "3"),
new ArrayList<String>(message.getStringToInt32Field().keySet()));
}
@@ -979,7 +976,8 @@
assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
- assertEquals(MessageValue.newBuilder().setValue(11).build(),
+ assertEquals(
+ MessageValue.newBuilder().setValue(11).build(),
testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
@@ -1037,7 +1035,8 @@
// expected
}
- assertEquals(MessageValue.newBuilder().setValue(11).build(),
+ assertEquals(
+ MessageValue.newBuilder().setValue(11).build(),
testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
try {
testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
@@ -1146,15 +1145,20 @@
// Regression test for b/20494788
public void testMapInitializationOrder() throws Exception {
- assertEquals("RedactAllTypes", map_test.RedactAllTypes
- .getDefaultInstance().getDescriptorForType().getName());
+ assertEquals(
+ "RedactAllTypes",
+ map_test.RedactAllTypes.getDefaultInstance()
+ .getDescriptorForType()
+ .getName());
map_test.Message1.Builder builder =
map_test.Message1.newBuilder();
builder.putMapField("key", true);
map_test.Message1 message = builder.build();
- Message mapEntry = (Message) message.getRepeatedField(
- message.getDescriptorForType().findFieldByName("map_field"), 0);
+ Message mapEntry =
+ (Message)
+ message.getRepeatedField(
+ message.getDescriptorForType().findFieldByName("map_field"), 0);
assertEquals(2, mapEntry.getAllFields().size());
}
@@ -1163,35 +1167,14 @@
ReservedAsMapFieldWithEnumValue.newBuilder().build();
}
- private static <K, V> Map<K, V> newMap(K key1, V value1) {
- Map<K, V> map = new HashMap<K, V>();
- map.put(key1, value1);
- return map;
- }
-
- private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
- Map<K, V> map = new HashMap<K, V>();
- map.put(key1, value1);
- map.put(key2, value2);
- return map;
- }
-
public void testGetMap() {
TestMap.Builder builder = TestMap.newBuilder();
setMapValuesUsingAccessors(builder);
assertMapValuesSet(builder);
TestMap message = builder.build();
- assertEquals(
- message.getStringToInt32Field(),
- message.getStringToInt32FieldMap());
- assertEquals(
- message.getInt32ToBytesField(),
- message.getInt32ToBytesFieldMap());
- assertEquals(
- message.getInt32ToEnumField(),
- message.getInt32ToEnumFieldMap());
- assertEquals(
- message.getInt32ToMessageField(),
- message.getInt32ToMessageFieldMap());
+ assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
+ assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
+ assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
+ assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
}
}
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index ef8b27e..6007d8e 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -477,12 +477,12 @@
}
public void testPutForUnknownEnumValues() throws Exception {
- TestMap.Builder builder =
+ TestMap message =
TestMap.newBuilder()
.putInt32ToEnumFieldValue(0, 0)
.putInt32ToEnumFieldValue(1, 1)
- .putInt32ToEnumFieldValue(2, 1000); // unknown value.
- TestMap message = builder.build();
+ .putInt32ToEnumFieldValue(2, 1000) // unknown value.
+ .build();
assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
@@ -608,12 +608,12 @@
// We can't control the order of elements in a HashMap. The best we can do
// here is to add elements in different order.
- TestMap.Builder b1 =
+ TestMap m1 =
TestMap.newBuilder()
.putInt32ToInt32Field(1, 2)
.putInt32ToInt32Field(3, 4)
- .putInt32ToInt32Field(5, 6);
- TestMap m1 = b1.build();
+ .putInt32ToInt32Field(5, 6)
+ .build();
TestMap.Builder b2 =
TestMap.newBuilder()
@@ -654,8 +654,8 @@
assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
// Make another change using mergeFrom()
- TestMap.Builder other = TestMap.newBuilder().putInt32ToInt32Field(1, 4);
- parent.getOptionalMessageBuilder().mergeFrom(other.build());
+ TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
+ parent.getOptionalMessageBuilder().mergeFrom(other);
// Should be able to observe the change.
message = parent.build();
@@ -751,7 +751,7 @@
}
private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
- List<Message> entryList = new ArrayList<Message>();
+ List<Message> entryList = new ArrayList<>();
for (Map.Entry<?, ?> entry : values.entrySet()) {
entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
}
@@ -760,7 +760,7 @@
}
private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
- Map<K, V> map = new HashMap<K, V>();
+ Map<K, V> map = new HashMap<>();
map.put(key1, value1);
map.put(key2, value2);
return map;
@@ -1002,8 +1002,7 @@
TestMap message = builder.build();
assertEquals(
- Arrays.asList("1", "2", "3"),
- new ArrayList<String>(message.getStringToInt32Field().keySet()));
+ Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet()));
}
public void testGetMap() {
@@ -1336,10 +1335,10 @@
output.flush();
CodedInputStream input = CodedInputStream.newInstance(serialized);
- List<Integer> int32Keys = new ArrayList<Integer>();
- List<Integer> uint32Keys = new ArrayList<Integer>();
- List<Long> int64Keys = new ArrayList<Long>();
- List<String> stringKeys = new ArrayList<String>();
+ List<Integer> int32Keys = new ArrayList<>();
+ List<Integer> uint32Keys = new ArrayList<>();
+ List<Long> int64Keys = new ArrayList<>();
+ List<String> stringKeys = new ArrayList<>();
int tag;
while (true) {
tag = input.readTag();
@@ -1450,20 +1449,20 @@
}
private static <K, V> Map<K, V> newMap(K key1, V value1) {
- Map<K, V> map = new HashMap<K, V>();
+ Map<K, V> map = new HashMap<>();
map.put(key1, value1);
return map;
}
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
- Map<K, V> map = new HashMap<K, V>();
+ Map<K, V> map = new HashMap<>();
map.put(key1, value1);
map.put(key2, value2);
return map;
}
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
- Map<K, V> map = new HashMap<K, V>();
+ Map<K, V> map = new HashMap<>();
map.put(key1, value1);
map.put(key2, value2);
map.put(key3, value3);
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
index 4a68c8b..304261c 100644
--- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -385,12 +385,12 @@
}
@Override
- public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ public void write(ByteBuffer value) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public void write(ByteBuffer value) throws IOException {
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
throw new UnsupportedOperationException();
}
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
index 1e89111..983caec 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -58,8 +58,7 @@
}
}
- private void assertRoundTripEquals(MessageLite message,
- ExtensionRegistryLite registry)
+ private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry)
throws Exception {
final byte[] data = message.toByteArray();
final int offset = 20;
@@ -67,15 +66,12 @@
final int padding = 30;
Parser<? extends MessageLite> parser = message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data, registry));
- assertMessageEquals(message, parser.parseFrom(
- generatePaddingArray(data, offset, padding),
- offset, length, registry));
- assertMessageEquals(message, parser.parseFrom(
- message.toByteString(), registry));
- assertMessageEquals(message, parser.parseFrom(
- new ByteArrayInputStream(data), registry));
- assertMessageEquals(message, parser.parseFrom(
- CodedInputStream.newInstance(data), registry));
+ assertMessageEquals(
+ message,
+ parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry));
+ assertMessageEquals(message, parser.parseFrom(message.toByteString(), registry));
+ assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry));
+ assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry));
assertMessageEquals(
message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
}
@@ -87,23 +83,17 @@
final int length = data.length;
final int padding = 30;
- Parser<MessageLite> parser =
- (Parser<MessageLite>) message.getParserForType();
+ Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data));
- assertMessageEquals(message, parser.parseFrom(
- generatePaddingArray(data, offset, padding),
- offset, length));
+ assertMessageEquals(
+ message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length));
assertMessageEquals(message, parser.parseFrom(message.toByteString()));
- assertMessageEquals(message, parser.parseFrom(
- new ByteArrayInputStream(data)));
- assertMessageEquals(message, parser.parseFrom(
- CodedInputStream.newInstance(data)));
+ assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data)));
+ assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data)));
assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
}
- private void assertMessageEquals(
- MessageLite expected, MessageLite actual)
- throws Exception {
+ private void assertMessageEquals(MessageLite expected, MessageLite actual) throws Exception {
if (expected instanceof Message) {
assertEquals(expected, actual);
} else {
@@ -126,20 +116,16 @@
assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
}
- private <T extends MessageLite> void assertParsePartial(
- Parser<T> parser, T partialMessage) throws Exception {
- final String errorString =
- "Should throw exceptions when the parsed message isn't initialized.";
+ private <T extends MessageLite> void assertParsePartial(Parser<T> parser, T partialMessage)
+ throws Exception {
+ final String errorString = "Should throw exceptions when the parsed message isn't initialized.";
// parsePartialFrom should pass.
byte[] data = partialMessage.toByteArray();
assertEquals(partialMessage, parser.parsePartialFrom(data));
- assertEquals(partialMessage, parser.parsePartialFrom(
- partialMessage.toByteString()));
- assertEquals(partialMessage, parser.parsePartialFrom(
- new ByteArrayInputStream(data)));
- assertEquals(partialMessage, parser.parsePartialFrom(
- CodedInputStream.newInstance(data)));
+ assertEquals(partialMessage, parser.parsePartialFrom(partialMessage.toByteString()));
+ assertEquals(partialMessage, parser.parsePartialFrom(new ByteArrayInputStream(data)));
+ assertEquals(partialMessage, parser.parsePartialFrom(CodedInputStream.newInstance(data)));
// parseFrom(ByteArray)
try {
@@ -167,8 +153,7 @@
// parseFrom(CodedInputStream)
try {
- parser.parseFrom(CodedInputStream.newInstance(
- partialMessage.toByteArray()));
+ parser.parseFrom(CodedInputStream.newInstance(partialMessage.toByteArray()));
fail(errorString);
} catch (IOException e) {
// pass.
@@ -176,14 +161,12 @@
}
public void testParseExtensions() throws Exception {
- assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
- TestUtil.getExtensionRegistry());
+ assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry());
}
public void testParsePacked() throws Exception {
assertRoundTripEquals(TestUtil.getPackedSet());
- assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
- TestUtil.getExtensionRegistry());
+ assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry());
}
public void testParseDelimitedTo() throws Exception {
@@ -202,9 +185,7 @@
// All fields will be treated as unknown fields in emptyMessage.
TestEmptyMessage emptyMessage =
TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString());
- assertEquals(
- TestUtil.getAllSet().toByteString(),
- emptyMessage.toByteString());
+ assertEquals(TestUtil.getAllSet().toByteString(), emptyMessage.toByteString());
}
@@ -212,7 +193,8 @@
TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
builder.setExtension(TestOptimizedForSize.testExtension, 56);
- builder.setExtension(TestOptimizedForSize.testExtension2,
+ builder.setExtension(
+ TestOptimizedForSize.testExtension2,
TestRequiredOptimizedForSize.newBuilder().setX(78).build());
TestOptimizedForSize message = builder.build();
@@ -222,9 +204,8 @@
assertRoundTripEquals(message, registry);
}
- /** Helper method for {@link #testParsingMerge()}.*/
- private void assertMessageMerged(TestAllTypes allTypes)
- throws Exception {
+ /** Helper method for {@link #testParsingMerge()}. */
+ private void assertMessageMerged(TestAllTypes allTypes) throws Exception {
assertEquals(3, allTypes.getOptionalInt32());
assertEquals(2, allTypes.getOptionalInt64());
assertEquals("hello", allTypes.getOptionalString());
@@ -237,39 +218,48 @@
builder.clear();
TestAllTypes msg2 = builder.setOptionalInt64(2).build();
builder.clear();
- TestAllTypes msg3 = builder.setOptionalInt32(3)
- .setOptionalString("hello").build();
+ TestAllTypes msg3 = builder.setOptionalInt32(3).setOptionalString("hello").build();
// Build groups.
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
- TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg1).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
- TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg2).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
- TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg3).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg3).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
- TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg1).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
- TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg2).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
- TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg3).build();
+ TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg3).build();
// Assign and serialize RepeatedFieldsGenerator.
- ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
- .addField1(msg1).addField1(msg2).addField1(msg3)
- .addField2(msg1).addField2(msg2).addField2(msg3)
- .addField3(msg1).addField3(msg2).addField3(msg3)
- .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
- .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
- .addExt1(msg1).addExt1(msg2).addExt1(msg3)
- .addExt2(msg1).addExt2(msg2).addExt2(msg3)
- .build().toByteString();
+ ByteString data =
+ TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
+ .addField1(msg1)
+ .addField1(msg2)
+ .addField1(msg3)
+ .addField2(msg1)
+ .addField2(msg2)
+ .addField2(msg3)
+ .addField3(msg1)
+ .addField3(msg2)
+ .addField3(msg3)
+ .addGroup1(optionalG1)
+ .addGroup1(optionalG2)
+ .addGroup1(optionalG3)
+ .addGroup2(repeatedG1)
+ .addGroup2(repeatedG2)
+ .addGroup2(repeatedG3)
+ .addExt1(msg1)
+ .addExt1(msg2)
+ .addExt1(msg3)
+ .addExt2(msg1)
+ .addExt2(msg2)
+ .addExt2(msg3)
+ .build()
+ .toByteString();
// Parse TestParsingMerge.
ExtensionRegistry registry = ExtensionRegistry.newInstance();
@@ -279,21 +269,18 @@
// Required and optional fields should be merged.
assertMessageMerged(parsingMerge.getRequiredAllTypes());
assertMessageMerged(parsingMerge.getOptionalAllTypes());
- assertMessageMerged(
- parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
- assertMessageMerged(parsingMerge.getExtension(
- TestParsingMerge.optionalExt));
+ assertMessageMerged(parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+ assertMessageMerged(parsingMerge.getExtension(TestParsingMerge.optionalExt));
// Repeated fields should not be merged.
assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
assertEquals(3, parsingMerge.getRepeatedGroupCount());
- assertEquals(3, parsingMerge.getExtensionCount(
- TestParsingMerge.repeatedExt));
+ assertEquals(3, parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt));
}
public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
try {
- TestUtil.getAllSet().parseDelimitedFrom(
+ TestAllTypes.parseDelimitedFrom(
new InputStream() {
@Override
public int read() throws IOException {
@@ -308,7 +295,7 @@
public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
try {
- TestUtil.getAllSet().parseDelimitedFrom(
+ TestAllTypes.parseDelimitedFrom(
new InputStream() {
private int i;
diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
index 1e58332..d9a6d7c 100644
--- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -58,9 +58,9 @@
private RpcController mockController;
private final Descriptors.MethodDescriptor fooDescriptor =
- TestService.getDescriptor().getMethods().get(0);
+ TestService.getDescriptor().getMethods().get(0);
private final Descriptors.MethodDescriptor barDescriptor =
- TestService.getDescriptor().getMethods().get(1);
+ TestService.getDescriptor().getMethods().get(1);
@Override
protected void setUp() throws Exception {
@@ -79,16 +79,22 @@
MockCallback<Message> barCallback = new MockCallback<Message>();
TestService mockService = control.createMock(TestService.class);
- mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
- this.<FooResponse>wrapsCallback(fooCallback));
- mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
- this.<BarResponse>wrapsCallback(barCallback));
+ mockService.foo(
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ this.<FooResponse>wrapsCallback(fooCallback));
+ mockService.bar(
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ this.<BarResponse>wrapsCallback(barCallback));
control.replay();
- mockService.callMethod(fooDescriptor, mockController,
- fooRequest, fooCallback);
- mockService.callMethod(barDescriptor, mockController,
- barRequest, barCallback);
+ mockService.callMethod(
+ fooDescriptor, mockController,
+ fooRequest, fooCallback);
+ mockService.callMethod(
+ barDescriptor, mockController,
+ barRequest, barCallback);
control.verify();
}
@@ -96,14 +102,10 @@
public void testGetPrototype() throws Exception {
TestService mockService = control.createMock(TestService.class);
- assertSame(mockService.getRequestPrototype(fooDescriptor),
- FooRequest.getDefaultInstance());
- assertSame(mockService.getResponsePrototype(fooDescriptor),
- FooResponse.getDefaultInstance());
- assertSame(mockService.getRequestPrototype(barDescriptor),
- BarRequest.getDefaultInstance());
- assertSame(mockService.getResponsePrototype(barDescriptor),
- BarResponse.getDefaultInstance());
+ assertSame(mockService.getRequestPrototype(fooDescriptor), FooRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(fooDescriptor), FooResponse.getDefaultInstance());
+ assertSame(mockService.getRequestPrototype(barDescriptor), BarRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(barDescriptor), BarResponse.getDefaultInstance());
}
/** Tests generated stubs. */
@@ -116,17 +118,17 @@
TestService stub = TestService.newStub(mockChannel);
mockChannel.callMethod(
- EasyMock.same(fooDescriptor),
- EasyMock.same(mockController),
- EasyMock.same(fooRequest),
- EasyMock.same(FooResponse.getDefaultInstance()),
- this.<Message>wrapsCallback(fooCallback));
+ EasyMock.same(fooDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ EasyMock.same(FooResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(fooCallback));
mockChannel.callMethod(
- EasyMock.same(barDescriptor),
- EasyMock.same(mockController),
- EasyMock.same(barRequest),
- EasyMock.same(BarResponse.getDefaultInstance()),
- this.<Message>wrapsCallback(barCallback));
+ EasyMock.same(barDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ EasyMock.same(BarResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(barCallback));
control.replay();
stub.foo(mockController, fooRequest, fooCallback);
@@ -138,24 +140,26 @@
public void testBlockingStub() throws Exception {
FooRequest fooRequest = FooRequest.newBuilder().build();
BarRequest barRequest = BarRequest.newBuilder().build();
- BlockingRpcChannel mockChannel =
- control.createMock(BlockingRpcChannel.class);
- TestService.BlockingInterface stub =
- TestService.newBlockingStub(mockChannel);
+ BlockingRpcChannel mockChannel = control.createMock(BlockingRpcChannel.class);
+ TestService.BlockingInterface stub = TestService.newBlockingStub(mockChannel);
FooResponse fooResponse = FooResponse.newBuilder().build();
BarResponse barResponse = BarResponse.newBuilder().build();
- EasyMock.expect(mockChannel.callBlockingMethod(
- EasyMock.same(fooDescriptor),
- EasyMock.same(mockController),
- EasyMock.same(fooRequest),
- EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
- EasyMock.expect(mockChannel.callBlockingMethod(
- EasyMock.same(barDescriptor),
- EasyMock.same(mockController),
- EasyMock.same(barRequest),
- EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
+ EasyMock.expect(
+ mockChannel.callBlockingMethod(
+ EasyMock.same(fooDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ EasyMock.same(FooResponse.getDefaultInstance())))
+ .andReturn(fooResponse);
+ EasyMock.expect(
+ mockChannel.callBlockingMethod(
+ EasyMock.same(barDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ EasyMock.same(BarResponse.getDefaultInstance())))
+ .andReturn(barResponse);
control.replay();
assertSame(fooResponse, stub.foo(mockController, fooRequest));
@@ -164,13 +168,11 @@
}
public void testNewReflectiveService() {
- ServiceWithNoOuter.Interface impl =
- control.createMock(ServiceWithNoOuter.Interface.class);
+ ServiceWithNoOuter.Interface impl = control.createMock(ServiceWithNoOuter.Interface.class);
RpcController controller = control.createMock(RpcController.class);
Service service = ServiceWithNoOuter.newReflectiveService(impl);
- MethodDescriptor fooMethod =
- ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+ MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
RpcCallback<Message> callback =
new RpcCallback<Message>() {
@@ -180,11 +182,9 @@
fail();
}
};
- RpcCallback<TestAllTypes> specializedCallback =
- RpcUtil.specializeCallback(callback);
+ RpcCallback<TestAllTypes> specializedCallback = RpcUtil.specializeCallback(callback);
- impl.foo(EasyMock.same(controller), EasyMock.same(request),
- EasyMock.same(specializedCallback));
+ impl.foo(EasyMock.same(controller), EasyMock.same(request), EasyMock.same(specializedCallback));
EasyMock.expectLastCall();
control.replay();
@@ -198,11 +198,9 @@
ServiceWithNoOuter.BlockingInterface impl =
control.createMock(ServiceWithNoOuter.BlockingInterface.class);
RpcController controller = control.createMock(RpcController.class);
- BlockingService service =
- ServiceWithNoOuter.newReflectiveBlockingService(impl);
+ BlockingService service = ServiceWithNoOuter.newReflectiveBlockingService(impl);
- MethodDescriptor fooMethod =
- ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+ MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
@@ -211,8 +209,7 @@
control.replay();
- Message response =
- service.callBlockingMethod(fooMethod, controller, request);
+ Message response = service.callBlockingMethod(fooMethod, controller, request);
assertEquals(expectedResponse, response);
control.verify();
@@ -221,16 +218,16 @@
public void testNoGenericServices() throws Exception {
// Non-services should be usable.
UnittestNoGenericServices.TestMessage message =
- UnittestNoGenericServices.TestMessage.newBuilder()
- .setA(123)
- .setExtension(UnittestNoGenericServices.testExtension, 456)
- .build();
+ UnittestNoGenericServices.TestMessage.newBuilder()
+ .setA(123)
+ .setExtension(UnittestNoGenericServices.testExtension, 456)
+ .build();
assertEquals(123, message.getA());
assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
// Build a list of the class names nested in UnittestNoGenericServices.
- String outerName = "google.protobuf.no_generic_services_test." +
- "UnittestNoGenericServices";
+ String outerName =
+ "google.protobuf.no_generic_services_test.UnittestNoGenericServices";
Class<?> outerClass = Class.forName(outerName);
Set<String> innerClassNames = new HashSet<String>();
@@ -244,9 +241,9 @@
// separator.
assertTrue(fullName.startsWith(outerName));
- if (!Service.class.isAssignableFrom(innerClass) &&
- !Message.class.isAssignableFrom(innerClass) &&
- !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
+ if (!Service.class.isAssignableFrom(innerClass)
+ && !Message.class.isAssignableFrom(innerClass)
+ && !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
// Ignore any classes not generated by the base code generator.
continue;
}
@@ -264,8 +261,7 @@
assertEquals(1, file.getServices().size());
assertEquals("TestService", file.getServices().get(0).getName());
assertEquals(1, file.getServices().get(0).getMethods().size());
- assertEquals("Foo",
- file.getServices().get(0).getMethods().get(0).getName());
+ assertEquals("Foo", file.getServices().get(0).getMethods().get(0).getName());
}
@@ -284,13 +280,18 @@
private static class MockCallback<T extends Message> implements RpcCallback<T> {
private boolean called = false;
- public boolean isCalled() { return called; }
+ public boolean isCalled() {
+ return called;
+ }
- public void reset() { called = false; }
+ public void reset() {
+ called = false;
+ }
@Override
public void run(T message) {
- called = true; }
+ called = true;
+ }
}
/** Implementation of the wrapsCallback() argument matcher. */
@@ -307,7 +308,7 @@
if (!(actual instanceof RpcCallback)) {
return false;
}
- RpcCallback actualCallback = (RpcCallback)actual;
+ RpcCallback actualCallback = (RpcCallback) actual;
callback.reset();
actualCallback.run(null);
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 48ee957..36e5eea 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -119,8 +119,6 @@
import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
-import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
-import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
import static protobuf_unittest.UnittestProto.defaultBoolExtension;
import static protobuf_unittest.UnittestProto.defaultBytesExtension;
import static protobuf_unittest.UnittestProto.defaultCordExtension;
@@ -222,6 +220,8 @@
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import protobuf_unittest.UnittestProto.RepeatedGroup_extension;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -234,6 +234,11 @@
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
import junit.framework.Assert;
/**
@@ -2634,7 +2639,6 @@
break;
case FOO_NOT_SET:
break;
- default:
// TODO(b/18683919): go/enum-switch-lsc
}
}
@@ -2702,7 +2706,7 @@
this.publicImportFile = importFile.getDependencies().get(0);
Descriptors.Descriptor testAllTypes;
- if (baseDescriptor.getName() == "TestAllTypes") {
+ if ("TestAllTypes".equals(baseDescriptor.getName())) {
testAllTypes = baseDescriptor;
} else {
testAllTypes = file.findMessageTypeByName("TestAllTypes");
@@ -3857,4 +3861,28 @@
}
}
// END FULL-RUNTIME
+
+ /** Helper class to test logged messages */
+ public static class TestLogHandler extends Handler {
+ /** We will keep a private list of all logged records */
+ private final List<LogRecord> list = new ArrayList<>();
+
+ /** Adds the most recently logged record to our list. */
+ @Override
+ public synchronized void publish(LogRecord record) {
+ list.add(record);
+ }
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public void close() {}
+
+ /** Returns a snapshot of the logged records. */
+ public synchronized List<LogRecord> getStoredLogRecords() {
+ List<LogRecord> result = new ArrayList<>(list);
+ return Collections.unmodifiableList(result);
+ }
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index d240088..2fad0b9 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -49,6 +49,7 @@
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import java.io.StringReader;
import java.util.List;
+import java.util.logging.Logger;
import junit.framework.TestCase;
/**
@@ -131,6 +132,8 @@
+ " i: 456\n"
+ "}\n";
+ private final TextFormat.Parser parserAllowingUnknownExtensions =
+ TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build();
private final TextFormat.Parser parserWithOverwriteForbidden =
TextFormat.Parser.newBuilder()
@@ -467,7 +470,7 @@
fail("expected parse exception");
} catch (TextFormat.ParseException e) {
assertEquals(
- "6:1: Non-repeated field "
+ "4:44: Non-repeated field "
+ "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+ " cannot be overwritten.",
e.getMessage());
@@ -519,6 +522,23 @@
}
+ private void assertParseErrorWithUnknownExtensions(String error, String text) {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ parserAllowingUnknownExtensions.merge(text, builder);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals(error, e.getMessage());
+ }
+ }
+
+ private TestAllTypes assertParseSuccessWithUnknownExtensions(String text)
+ throws TextFormat.ParseException {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ parserAllowingUnknownExtensions.merge(text, builder);
+ return builder.build();
+ }
+
private void assertParseErrorWithOverwriteForbidden(String error, String text) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
@@ -954,6 +974,54 @@
}
+ public void testParseUnknownExtensions() throws Exception {
+ TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
+ Logger logger = Logger.getLogger(TextFormat.class.getName());
+ logger.addHandler(logHandler);
+ // Test unknown extension can pass.
+ assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123");
+ assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123\n"
+ + "[unknown_ext]: inf\n"
+ + "[unknown]: 1.234");
+ // Test warning messages.
+ assertEquals("Input contains unknown fields and/or extensions:\n"
+ + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]",
+ logHandler.getStoredLogRecords().get(0).getMessage());
+ assertEquals("Input contains unknown fields and/or extensions:\n"
+ + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
+ + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]",
+ logHandler.getStoredLogRecords().get(1).getMessage());
+
+ // Test unknown field can not pass.
+ assertParseErrorWithUnknownExtensions(
+ "2:1: Input contains unknown fields and/or extensions:\n"
+ + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field",
+ "[unknown_extension]: 1\n"
+ + "unknown_field: 12345");
+ assertParseErrorWithUnknownExtensions(
+ "3:1: Input contains unknown fields and/or extensions:\n"
+ + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension1]\n"
+ + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension2]\n"
+ + "3:1:\tprotobuf_unittest.TestAllTypes.unknown_field\n"
+ + "4:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension3]",
+ "[unknown_extension1]: 1\n"
+ + "[unknown_extension2]: 2\n"
+ + "unknown_field: 12345\n"
+ + "[unknown_extension3]: 3\n");
+ assertParseErrorWithUnknownExtensions(
+ "1:1: Input contains unknown fields and/or extensions:\n"
+ + "1:1:\tprotobuf_unittest.TestAllTypes.unknown_field1\n"
+ + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field2\n"
+ + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ + "4:1:\tprotobuf_unittest.TestAllTypes.unknown_field3",
+ "unknown_field1: 1\n"
+ + "unknown_field2: 2\n"
+ + "[unknown_extension]: 12345\n"
+ + "unknown_field3: 3\n");
+ }
+
// See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
public void testParseNonRepeatedFields() throws Exception {
assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n");
@@ -962,29 +1030,29 @@
"repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n");
assertParseErrorWithOverwriteForbidden(
- "3:17: Non-repeated field "
+ "3:15: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optional_int32\" "
+ "cannot be overwritten.",
"optional_int32: 1\noptional_bool: true\noptional_int32: 1\n");
assertParseErrorWithOverwriteForbidden(
- "2:17: Non-repeated field "
+ "2:1: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optionalgroup\" "
+ "cannot be overwritten.",
"OptionalGroup { a: 1 }\nOptionalGroup { }\n");
assertParseErrorWithOverwriteForbidden(
- "2:33: Non-repeated field "
+ "2:1: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optional_nested_message\" "
+ "cannot be overwritten.",
"optional_nested_message { }\noptional_nested_message { bb: 3 }\n");
assertParseErrorWithOverwriteForbidden(
- "2:16: Non-repeated field "
+ "2:14: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.default_int32\" "
+ "cannot be overwritten.",
"default_int32: 41\n"
+ // the default value
"default_int32: 41\n");
assertParseErrorWithOverwriteForbidden(
- "2:17: Non-repeated field "
+ "2:15: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.default_string\" "
+ "cannot be overwritten.",
"default_string: \"zxcv\"\ndefault_string: \"asdf\"\n");
@@ -1044,7 +1112,7 @@
fail("Expected parse exception.");
} catch (TextFormat.ParseException e) {
assertEquals(
- "1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
+ "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
+ " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+ " another member of oneof \"foo\".",
e.getMessage());
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index 86630f6..6316bd8 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -353,8 +353,8 @@
/**
* Asserts that the given field sets are not equal and have different hash codes.
*
- * @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
- * than it needs to be. However, this should happen relatively rarely.
+ * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
+ * stricter than it needs to be. However, this should happen relatively rarely.
*/
private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
String equalsError = String.format("%s should not be equal to %s", s1, s2);
diff --git a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
index 00f201c..bc73cc9 100644
--- a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
@@ -42,13 +42,13 @@
*/
public class UnmodifiableLazyStringListTest extends TestCase {
- private static String STRING_A = "A";
- private static String STRING_B = "B";
- private static String STRING_C = "C";
+ private static final String STRING_A = "A";
+ private static final String STRING_B = "B";
+ private static final String STRING_C = "C";
- private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
- private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
- private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
+ private static final ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
+ private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
+ private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
public void testReadOnlyMethods() {
LazyStringArrayList rawList = createSampleList();
diff --git a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
index 2367bd8..28f3658 100644
--- a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
@@ -53,7 +53,7 @@
NestedEnum optional_nested_enum = 4;
NestedMessage optional_nested_message = 5;
protobuf_unittest.TestRequired optional_proto2_message = 6;
- NestedMessage optional_lazy_message = 7 [lazy=true];
+ NestedMessage optional_lazy_message = 7 [lazy = true];
oneof oneof_field {
int32 oneof_int32 = 11;
@@ -81,7 +81,7 @@
TestAllTypes.NestedEnum optional_nested_enum = 4;
TestAllTypes.NestedMessage optional_nested_message = 5;
protobuf_unittest.TestRequired optional_proto2_message = 6;
- TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy=true];
+ TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy = true];
}
message TestRepeatedFieldsOnly {
diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
index 20fa03b..080c519 100644
--- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
+++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
@@ -69,8 +69,7 @@
optional string name = 1;
}
-message Empty {
-}
+message Empty {}
extend Foo {
optional int32 varint = 101;
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
index 2ca0251..4ec9688 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -44,12 +44,12 @@
QUX = 3;
}
- map<int32, int32> int32_to_int32_field = 1;
- map<int32, string> int32_to_string_field = 2;
- map<int32, bytes> int32_to_bytes_field = 3;
- map<int32, EnumValue> int32_to_enum_field = 4;
- map<int32, MessageValue> int32_to_message_field = 5;
- map<string, int32> string_to_int32_field = 6;
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
message MessageWithRequiredFields {
required int32 value = 1;
@@ -70,15 +70,20 @@
map<int32, TestRecursiveMap> recursive_map_field = 2;
}
-
// a decoy of TestMap for testing parsing errors
message BizarroTestMap {
- map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
- map<string, int32> int32_to_string_field = 2; // different key and value types
- map<string, int32> int32_to_bytes_field = 3; // different key types, same value
- map<string, bytes> int32_to_enum_field = 4; // different key and value types
- map<string, bytes> int32_to_message_field = 5; // different key and value types
- map<string, bytes> string_to_int32_field = 6; // same key type, different value
+ // same key type, different value
+ map<int32, bytes> int32_to_int32_field = 1;
+ // different key and value types
+ map<string, int32> int32_to_string_field = 2;
+ // different key types, same value
+ map<string, int32> int32_to_bytes_field = 3;
+ // different key and value types
+ map<string, bytes> int32_to_enum_field = 4;
+ // different key and value types
+ map<string, bytes> int32_to_message_field = 5;
+ // same key type, different value
+ map<string, bytes> string_to_int32_field = 6;
}
// Used to test that java reserved words can be used as protobuf field names
@@ -92,11 +97,13 @@
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
- map<string, uint32> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, uint32> string = 7;
map<string, uint32> package = 8;
- map<string, uint32> enum = 9; // Most recent Java reserved word
- map<string, uint32> null = 10;
+ // Most recent Java reserved word
+ map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, uint32> null = 10;
}
message ReservedAsMapFieldWithEnumValue {
@@ -110,11 +117,13 @@
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
- map<string, SampleEnum> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8;
- map<string, SampleEnum> enum = 9; // Most recent Java reserved word
- map<string, SampleEnum> null = 10;
+ // Most recent Java reserved word
+ map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, SampleEnum> null = 10;
}
package map_for_proto2_lite_test;
option java_package = "map_lite_test";
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
index 974f8a2..f73bd63 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
@@ -46,12 +46,12 @@
QUX = 3;
}
- map<int32, int32> int32_to_int32_field = 1;
- map<int32, string> int32_to_string_field = 2;
- map<int32, bytes> int32_to_bytes_field = 3;
- map<int32, EnumValue> int32_to_enum_field = 4;
- map<int32, MessageValue> int32_to_message_field = 5;
- map<string, int32> string_to_int32_field = 6;
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
message MessageWithRequiredFields {
required int32 value = 1;
@@ -72,15 +72,20 @@
map<int32, TestRecursiveMap> recursive_map_field = 2;
}
-
// a decoy of TestMap for testing parsing errors
message BizarroTestMap {
- map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
- map<string, int32> int32_to_string_field = 2; // different key and value types
- map<string, int32> int32_to_bytes_field = 3; // different key types, same value
- map<string, bytes> int32_to_enum_field = 4; // different key and value types
- map<string, bytes> int32_to_message_field = 5; // different key and value types
- map<string, bytes> string_to_int32_field = 6; // same key type, different value
+ // same key type, different value
+ map<int32, bytes> int32_to_int32_field = 1;
+ // different key and value types
+ map<string, int32> int32_to_string_field = 2;
+ // different key types, same value
+ map<string, int32> int32_to_bytes_field = 3;
+ // different key and value types
+ map<string, bytes> int32_to_enum_field = 4;
+ // different key and value types
+ map<string, bytes> int32_to_message_field = 5;
+ // same key type, different value
+ map<string, bytes> string_to_int32_field = 6;
}
// Used to test that java reserved words can be used as protobuf field names
@@ -94,11 +99,13 @@
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
- map<string, uint32> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, uint32> string = 7;
map<string, uint32> package = 8;
- map<string, uint32> enum = 9; // Most recent Java reserved word
- map<string, uint32> null = 10;
+ // Most recent Java reserved word
+ map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, uint32> null = 10;
}
message ReservedAsMapFieldWithEnumValue {
@@ -112,9 +119,11 @@
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
- map<string, SampleEnum> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8;
- map<string, SampleEnum> enum = 9; // Most recent Java reserved word
- map<string, SampleEnum> null = 10;
+ // Most recent Java reserved word
+ map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, SampleEnum> null = 10;
}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
index b02ac59..6ebef5e 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
@@ -57,5 +57,4 @@
optional Message1 recursive_extension = 1001;
}
-message RedactAllTypes {
-}
+message RedactAllTypes {}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
index c04f5d5..7324653 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
@@ -47,14 +47,14 @@
QUX = 3;
}
- map<int32, int32> int32_to_int32_field = 1;
- map<int32, string> int32_to_string_field = 2;
- map<int32, bytes> int32_to_bytes_field = 3;
- map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
map<int32, MessageValue> int32_to_message_field = 5;
- map<string, int32> string_to_int32_field = 6;
- map<uint32, int32> uint32_to_int32_field = 7;
- map<int64, int32> int64_to_int32_field = 8;
+ map<string, int32> string_to_int32_field = 6;
+ map<uint32, int32> uint32_to_int32_field = 7;
+ map<int64, int32> int64_to_int32_field = 8;
}
// Used to test that a nested builder containing map fields will properly
@@ -66,12 +66,18 @@
// a decoy of TestMap for testing parsing errors
message BizarroTestMap {
- map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
- map<string, int32> int32_to_string_field = 2; // different key and value types
- map<string, int32> int32_to_bytes_field = 3; // different key types, same value
- map<string, bytes> int32_to_enum_field = 4; // different key and value types
- map<string, bytes> int32_to_message_field = 5; // different key and value types
- map<string, bytes> string_to_int32_field = 6; // same key type, different value
+ // same key type, different value
+ map<int32, bytes> int32_to_int32_field = 1;
+ // different key and value types
+ map<string, int32> int32_to_string_field = 2;
+ // different key types, same value
+ map<string, int32> int32_to_bytes_field = 3;
+ // different key and value types
+ map<string, bytes> int32_to_enum_field = 4;
+ // different key and value types
+ map<string, bytes> int32_to_message_field = 5;
+ // same key type, different value
+ map<string, bytes> string_to_int32_field = 6;
}
// Used to test that java reserved words can be used as protobuf field names
@@ -85,11 +91,13 @@
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
- map<string, uint32> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, uint32> string = 7;
map<string, uint32> package = 8;
- map<string, uint32> enum = 9; // Most recent Java reserved word
- map<string, uint32> null = 10;
+ // Most recent Java reserved word
+ map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, uint32> null = 10;
}
message ReservedAsMapFieldWithEnumValue {
@@ -103,9 +111,11 @@
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
- map<string, SampleEnum> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8;
- map<string, SampleEnum> enum = 9; // Most recent Java reserved word
- map<string, SampleEnum> null = 10;
+ // Most recent Java reserved word
+ map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, SampleEnum> null = 10;
}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
index bc2105e..240600f 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -46,14 +46,14 @@
QUX = 3;
}
- map<int32, int32> int32_to_int32_field = 1;
- map<int32, string> int32_to_string_field = 2;
- map<int32, bytes> int32_to_bytes_field = 3;
- map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
map<int32, MessageValue> int32_to_message_field = 5;
- map<string, int32> string_to_int32_field = 6;
- map<uint32, int32> uint32_to_int32_field = 7;
- map<int64, int32> int64_to_int32_field = 8;
+ map<string, int32> string_to_int32_field = 6;
+ map<uint32, int32> uint32_to_int32_field = 7;
+ map<int64, int32> int64_to_int32_field = 8;
}
// Used to test that a nested builder containing map fields will properly
@@ -65,12 +65,18 @@
// a decoy of TestMap for testing parsing errors
message BizarroTestMap {
- map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
- map<string, int32> int32_to_string_field = 2; // different key and value types
- map<string, int32> int32_to_bytes_field = 3; // different key types, same value
- map<string, bytes> int32_to_enum_field = 4; // different key and value types
- map<string, bytes> int32_to_message_field = 5; // different key and value types
- map<string, bytes> string_to_int32_field = 6; // same key type, different value
+ // same key type, different value
+ map<int32, bytes> int32_to_int32_field = 1;
+ // different key and value types
+ map<string, int32> int32_to_string_field = 2;
+ // different key types, same value
+ map<string, int32> int32_to_bytes_field = 3;
+ // different key and value types
+ map<string, bytes> int32_to_enum_field = 4;
+ // different key and value types
+ map<string, bytes> int32_to_message_field = 5;
+ // same key type, different value
+ map<string, bytes> string_to_int32_field = 6;
}
// Used to test that java reserved words can be used as protobuf field names
@@ -84,11 +90,13 @@
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
- map<string, uint32> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, uint32> string = 7;
map<string, uint32> package = 8;
- map<string, uint32> enum = 9; // Most recent Java reserved word
- map<string, uint32> null = 10;
+ // Most recent Java reserved word
+ map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, uint32> null = 10;
}
message ReservedAsMapFieldWithEnumValue {
@@ -102,9 +110,11 @@
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
- map<string, SampleEnum> string = 7; // These are also proto keywords
+ // These are also proto keywords
+ map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8;
- map<string, SampleEnum> enum = 9; // Most recent Java reserved word
- map<string, SampleEnum> null = 10;
+ // Most recent Java reserved word
+ map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care
+ map<string, SampleEnum> null = 10;
}
diff --git a/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
index a5dd66d..07933ed 100644
--- a/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
@@ -37,7 +37,6 @@
option java_multiple_files = true;
option java_outer_classname = "NestedBuilders";
-
message Vehicle {
optional Engine engine = 1;
repeated Wheel wheel = 2;
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
index 31fac55..39c2c07 100644
--- a/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
@@ -41,10 +41,8 @@
extensions 1 to max;
}
-message MyNonNestedExtension {
-}
+message MyNonNestedExtension {}
extend MessageToBeExtended {
optional MyNonNestedExtension nonNestedExtension = 1;
}
-
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
index 37c369e..e2ba46c 100644
--- a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
@@ -42,10 +42,8 @@
extensions 1 to max;
}
-message MyNonNestedExtensionLite {
-}
+message MyNonNestedExtensionLite {}
extend MessageLiteToBeExtended {
optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
}
-
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
index 4208368..28b8bb5 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
@@ -36,5 +36,4 @@
// This message's name is the same with the default outer class name of this
// proto file. It's used to test if the compiler can avoid this conflict
// correctly.
-message OuterClassNameTest {
-}
+message OuterClassNameTest {}
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
index 3e5956b..b475510 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
@@ -38,7 +38,6 @@
// This message's name is the same with the default outer class name of this
// proto file. It's used to test if the compiler can avoid this conflict
// correctly.
- message OuterClassNameTest2 {
- }
+ message OuterClassNameTest2 {}
}
}
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
index 74a8ba3..e5ef2f0 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
@@ -38,8 +38,6 @@
// This enum's name is the same with the default outer class name of this
// proto file. It's used to test if the compiler can avoid this conflict
// correctly.
- enum OuterClassNameTest3 {
- DUMMY_VALUE = 1;
- }
+ enum OuterClassNameTest3 { DUMMY_VALUE = 1; }
}
}
diff --git a/java/pom.xml b/java/pom.xml
index 070951a..c46e52b 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -86,6 +86,12 @@
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>26.0-jre</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 217ba16..bcf4f19 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -25,6 +25,11 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java
index 17b41cb..7836ccf 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Durations.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -30,6 +30,7 @@
package com.google.protobuf.util;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.IntMath.checkedAdd;
import static com.google.common.math.IntMath.checkedSubtract;
import static com.google.common.math.LongMath.checkedAdd;
@@ -53,6 +54,10 @@
static final long DURATION_SECONDS_MIN = -315576000000L;
static final long DURATION_SECONDS_MAX = 315576000000L;
+ private static final long SECONDS_PER_MINUTE = 60L;
+ private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60;
+ private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
+
/** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */
public static final Duration MIN_VALUE =
Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
@@ -118,6 +123,7 @@
* and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
* value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static boolean isValid(long seconds, int nanos) {
if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
return false;
@@ -133,6 +139,39 @@
return true;
}
+ /** Returns whether the given {@link Duration} is negative or not. */
+ public static boolean isNegative(Duration duration) {
+ checkValid(duration);
+ return (duration.getSeconds() == 0) ? duration.getNanos() < 0 : duration.getSeconds() < 0;
+ }
+
+ /**
+ * Ensures that the given {@link Duration} is not negative.
+ *
+ * @throws IllegalArgumentException if {@code duration} is negative or invalid
+ * @throws NullPointerException if {@code duration} is {@code null}
+ */
+ public static Duration checkNotNegative(Duration duration) {
+ checkValid(duration);
+ checkArgument(!isNegative(duration), "duration (%s) must not be negative", toString(duration));
+ return duration;
+ }
+
+ /**
+ * Ensures that the given {@link Duration} is positive.
+ *
+ * @throws IllegalArgumentException if {@code duration} is negative, {@code ZERO}, or invalid
+ * @throws NullPointerException if {@code duration} is {@code null}
+ */
+ public static Duration checkPositive(Duration duration) {
+ checkValid(duration);
+ checkArgument(
+ !isNegative(duration) && !duration.equals(ZERO),
+ "duration (%s) must be positive",
+ toString(duration));
+ return duration;
+ }
+
/** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
public static Duration checkValid(Duration duration) {
long seconds = duration.getSeconds();
@@ -216,30 +255,125 @@
}
}
+ // Static factories
+
+ /** Create a Duration from the number of days. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static Duration fromDays(long days) {
+ return Duration.newBuilder()
+ .setSeconds(checkedMultiply(days, SECONDS_PER_DAY))
+ .setNanos(0)
+ .build();
+ }
+
+ /** Create a Duration from the number of hours. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static Duration fromHours(long hours) {
+ return Duration.newBuilder()
+ .setSeconds(checkedMultiply(hours, SECONDS_PER_HOUR))
+ .setNanos(0)
+ .build();
+ }
+
+ /** Create a Duration from the number of minutes. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static Duration fromMinutes(long minutes) {
+ return Duration.newBuilder()
+ .setSeconds(checkedMultiply(minutes, SECONDS_PER_MINUTE))
+ .setNanos(0)
+ .build();
+ }
+
/** Create a Duration from the number of seconds. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromSeconds(long seconds) {
return normalizedDuration(seconds, 0);
}
- /**
- * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
- * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
- */
- public static long toSeconds(Duration duration) {
- return checkValid(duration).getSeconds();
- }
-
/** Create a Duration from the number of milliseconds. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromMillis(long milliseconds) {
return normalizedDuration(
milliseconds / MILLIS_PER_SECOND,
(int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
}
+ /** Create a Duration from the number of microseconds. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static Duration fromMicros(long microseconds) {
+ return normalizedDuration(
+ microseconds / MICROS_PER_SECOND,
+ (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+ }
+
+ /** Create a Duration from the number of nanoseconds. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static Duration fromNanos(long nanoseconds) {
+ return normalizedDuration(
+ nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+ }
+
+ // Conversion APIs
+
+ /**
+ * Convert a Duration to the number of days. The result will be rounded towards 0 to the nearest
+ * day.
+ */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static long toDays(Duration duration) {
+ return checkValid(duration).getSeconds() / SECONDS_PER_DAY;
+ }
+
+ /**
+ * Convert a Duration to the number of hours. The result will be rounded towards 0 to the nearest
+ * hour.
+ */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static long toHours(Duration duration) {
+ return checkValid(duration).getSeconds() / SECONDS_PER_HOUR;
+ }
+
+ /**
+ * Convert a Duration to the number of minutes. The result will be rounded towards 0 to the
+ * nearest minute.
+ */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static long toMinutes(Duration duration) {
+ return checkValid(duration).getSeconds() / SECONDS_PER_MINUTE;
+ }
+
+ /**
+ * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
+ * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
+ */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
+ public static long toSeconds(Duration duration) {
+ return checkValid(duration).getSeconds();
+ }
+
+ /**
+ * Returns the number of seconds of the given duration as a {@code double}. This method should be
+ * used to accommodate APIs that <b>only</b> accept durations as {@code double} values.
+ *
+ * <p>This conversion may lose precision.
+ *
+ * <p>If you need the number of seconds in this duration as a {@code long} (not a {@code double}),
+ * simply use {@code duration.getSeconds()} or {@link #toSeconds} (which includes validation).
+ */
+ @SuppressWarnings({
+ "DurationSecondsToDouble", // that's the whole point of this method
+ "GoodTime" // this is a legacy conversion API
+ })
+ public static double toSecondsAsDouble(Duration duration) {
+ checkValid(duration);
+ return duration.getSeconds() + duration.getNanos() / 1e9;
+ }
+
/**
* Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the
* nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMillis(Duration duration) {
checkValid(duration);
return checkedAdd(
@@ -247,17 +381,11 @@
duration.getNanos() / NANOS_PER_MILLISECOND);
}
- /** Create a Duration from the number of microseconds. */
- public static Duration fromMicros(long microseconds) {
- return normalizedDuration(
- microseconds / MICROS_PER_SECOND,
- (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
- }
-
/**
* Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the
* nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMicros(Duration duration) {
checkValid(duration);
return checkedAdd(
@@ -265,19 +393,16 @@
duration.getNanos() / NANOS_PER_MICROSECOND);
}
- /** Create a Duration from the number of nanoseconds. */
- public static Duration fromNanos(long nanoseconds) {
- return normalizedDuration(
- nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
- }
-
/** Convert a Duration to the number of nanoseconds. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toNanos(Duration duration) {
checkValid(duration);
return checkedAdd(
checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
}
+ // Math operations
+
/** Add two durations. */
public static Duration add(Duration d1, Duration d2) {
checkValid(d1);
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 46deb5d..3301e02 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -77,7 +77,9 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
+import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -106,7 +108,7 @@
public static Printer printer() {
return new Printer(
TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
- false, false, false);
+ false, false, false, false);
}
/**
@@ -127,6 +129,7 @@
private final boolean preservingProtoFieldNames;
private final boolean omittingInsignificantWhitespace;
private final boolean printingEnumsAsInts;
+ private final boolean sortingMapKeys;
private Printer(
TypeRegistry registry,
@@ -134,13 +137,15 @@
Set<FieldDescriptor> includingDefaultValueFields,
boolean preservingProtoFieldNames,
boolean omittingInsignificantWhitespace,
- boolean printingEnumsAsInts) {
+ boolean printingEnumsAsInts,
+ boolean sortingMapKeys) {
this.registry = registry;
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames;
this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
this.printingEnumsAsInts = printingEnumsAsInts;
+ this.sortingMapKeys = sortingMapKeys;
}
/**
@@ -159,7 +164,8 @@
includingDefaultValueFields,
preservingProtoFieldNames,
omittingInsignificantWhitespace,
- printingEnumsAsInts);
+ printingEnumsAsInts,
+ sortingMapKeys);
}
/**
@@ -176,7 +182,8 @@
Collections.<FieldDescriptor>emptySet(),
preservingProtoFieldNames,
omittingInsignificantWhitespace,
- printingEnumsAsInts);
+ printingEnumsAsInts,
+ sortingMapKeys);
}
/**
@@ -193,7 +200,8 @@
Collections.<FieldDescriptor>emptySet(),
preservingProtoFieldNames,
omittingInsignificantWhitespace,
- true);
+ true,
+ sortingMapKeys);
}
private void checkUnsetPrintingEnumsAsInts() {
@@ -221,7 +229,8 @@
fieldsToAlwaysOutput,
preservingProtoFieldNames,
omittingInsignificantWhitespace,
- printingEnumsAsInts);
+ printingEnumsAsInts,
+ sortingMapKeys);
}
private void checkUnsetIncludingDefaultValueFields() {
@@ -244,7 +253,8 @@
includingDefaultValueFields,
true,
omittingInsignificantWhitespace,
- printingEnumsAsInts);
+ printingEnumsAsInts,
+ sortingMapKeys);
}
@@ -272,7 +282,31 @@
includingDefaultValueFields,
preservingProtoFieldNames,
true,
- printingEnumsAsInts);
+ printingEnumsAsInts,
+ sortingMapKeys);
+ }
+
+ /**
+ * Create a new {@link Printer} that will sort the map keys in the JSON output.
+ *
+ * Use of this modifier is discouraged, the generated JSON messages are equivalent
+ * with and without this option set, but there are some corner caseuse cases that
+ * demand a stable output, while order of map keys is otherwise arbitrary.
+ *
+ * The generated order is not well-defined and should not be depended on, but
+ * it's stable.
+ *
+ * This new Printer clones all other configurations from the current {@link Printer}.
+ */
+ public Printer sortingMapKeys() {
+ return new Printer(
+ registry,
+ alwaysOutputDefaultValueFields,
+ includingDefaultValueFields,
+ preservingProtoFieldNames,
+ omittingInsignificantWhitespace,
+ printingEnumsAsInts,
+ true);
}
/**
@@ -292,7 +326,8 @@
preservingProtoFieldNames,
output,
omittingInsignificantWhitespace,
- printingEnumsAsInts)
+ printingEnumsAsInts,
+ sortingMapKeys)
.print(message);
}
@@ -604,6 +639,7 @@
private final Set<FieldDescriptor> includingDefaultValueFields;
private final boolean preservingProtoFieldNames;
private final boolean printingEnumsAsInts;
+ private final boolean sortingMapKeys;
private final TextGenerator generator;
// We use Gson to help handle string escapes.
private final Gson gson;
@@ -621,12 +657,14 @@
boolean preservingProtoFieldNames,
Appendable jsonOutput,
boolean omittingInsignificantWhitespace,
- boolean printingEnumsAsInts) {
+ boolean printingEnumsAsInts,
+ boolean sortingMapKeys) {
this.registry = registry;
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames;
this.printingEnumsAsInts = printingEnumsAsInts;
+ this.sortingMapKeys = sortingMapKeys;
this.gson = GsonHolder.DEFAULT_GSON;
// json format related properties, determined by printerType
if (omittingInsignificantWhitespace) {
@@ -957,8 +995,32 @@
}
generator.print("{" + blankOrNewLine);
generator.indent();
+
+ @SuppressWarnings("unchecked") // Object guaranteed to be a List for a map field.
+ Collection<Object> elements = (List<Object>) value;
+ if (sortingMapKeys && !elements.isEmpty()) {
+ Comparator<Object> cmp = null;
+ if (keyField.getType() == FieldDescriptor.Type.STRING) {
+ cmp = new Comparator<Object>() {
+ @Override
+ public int compare(final Object o1, final Object o2) {
+ ByteString s1 = ByteString.copyFromUtf8((String) o1);
+ ByteString s2 = ByteString.copyFromUtf8((String) o2);
+ return ByteString.unsignedLexicographicalComparator().compare(s1, s2);
+ }
+ };
+ }
+ TreeMap<Object, Object> tm = new TreeMap<Object, Object>(cmp);
+ for (Object element : elements) {
+ Message entry = (Message) element;
+ Object entryKey = entry.getField(keyField);
+ tm.put(entryKey, element);
+ }
+ elements = tm.values();
+ }
+
boolean printedElement = false;
- for (Object element : (List) value) {
+ for (Object element : elements) {
Message entry = (Message) element;
Object entryKey = entry.getField(keyField);
Object entryValue = entry.getField(valueField);
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
index 0475847..4ffb410 100644
--- a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -325,6 +325,7 @@
// Multiplications and divisions.
// TODO(kak): Delete this.
+ @SuppressWarnings("DurationSecondsToDouble")
public static Duration multiply(Duration duration, double times) {
double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0;
if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {
diff --git a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
index 9e528d4..83f3a9d 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -150,6 +150,7 @@
* <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
* nanos values that count forward in time.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static boolean isValid(long seconds, int nanos) {
if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
return false;
@@ -266,6 +267,7 @@
}
/** Create a Timestamp from the number of seconds elapsed from the epoch. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromSeconds(long seconds) {
return normalizedTimestamp(seconds, 0);
}
@@ -276,11 +278,13 @@
* <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents
* "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toSeconds(Timestamp timestamp) {
return checkValid(timestamp).getSeconds();
}
/** Create a Timestamp from the number of milliseconds elapsed from the epoch. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromMillis(long milliseconds) {
return normalizedTimestamp(
milliseconds / MILLIS_PER_SECOND,
@@ -293,6 +297,7 @@
* <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMillis(Timestamp timestamp) {
checkValid(timestamp);
return checkedAdd(
@@ -301,6 +306,7 @@
}
/** Create a Timestamp from the number of microseconds elapsed from the epoch. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromMicros(long microseconds) {
return normalizedTimestamp(
microseconds / MICROS_PER_SECOND,
@@ -313,6 +319,7 @@
* <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond.
*/
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMicros(Timestamp timestamp) {
checkValid(timestamp);
return checkedAdd(
@@ -321,12 +328,14 @@
}
/** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromNanos(long nanoseconds) {
return normalizedTimestamp(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
}
/** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */
+ @SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toNanos(Timestamp timestamp) {
checkValid(timestamp);
return checkedAdd(
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index 64413bc..6095068 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -156,6 +156,9 @@
private String toCompactJsonString(Message message) throws IOException {
return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
}
+ private String toSortedJsonString(Message message) throws IOException {
+ return JsonFormat.printer().sortingMapKeys().print(message);
+ }
private void mergeFromJson(String json, Message.Builder builder) throws IOException {
JsonFormat.parser().merge(json, builder);
@@ -1635,4 +1638,50 @@
// Expected.
}
}
+
+ public void testSortedMapKeys() throws Exception {
+ TestMap.Builder mapBuilder = TestMap.newBuilder();
+ mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0
+ mapBuilder.putStringToInt32Map("foo", 99);
+ mapBuilder.putStringToInt32Map("xxx", 123);
+ mapBuilder.putStringToInt32Map("\u20ac", 1); // utf-8 E2 82 AC
+ mapBuilder.putStringToInt32Map("abc", 20);
+ mapBuilder.putStringToInt32Map("19", 19);
+ mapBuilder.putStringToInt32Map("8", 8);
+ mapBuilder.putStringToInt32Map("\ufb00", 2); // utf-8 EF AC 80
+ mapBuilder.putInt32ToInt32Map(3, 3);
+ mapBuilder.putInt32ToInt32Map(10, 10);
+ mapBuilder.putInt32ToInt32Map(5, 5);
+ mapBuilder.putInt32ToInt32Map(4, 4);
+ mapBuilder.putInt32ToInt32Map(1, 1);
+ mapBuilder.putInt32ToInt32Map(2, 2);
+ mapBuilder.putInt32ToInt32Map(-3, -3);
+ TestMap mapMessage = mapBuilder.build();
+ assertEquals(
+ "{\n"
+ + " \"int32ToInt32Map\": {\n"
+ + " \"-3\": -3,\n"
+ + " \"1\": 1,\n"
+ + " \"2\": 2,\n"
+ + " \"3\": 3,\n"
+ + " \"4\": 4,\n"
+ + " \"5\": 5,\n"
+ + " \"10\": 10\n"
+ + " },\n"
+ + " \"stringToInt32Map\": {\n"
+ + " \"19\": 19,\n"
+ + " \"8\": 8,\n"
+ + " \"abc\": 20,\n"
+ + " \"foo\": 99,\n"
+ + " \"xxx\": 123,\n"
+ + " \"\u20ac\": 1,\n"
+ + " \"\ufb00\": 2,\n"
+ + " \"\ud834\udd20\": 3\n"
+ + " }\n"
+ + "}",
+ toSortedJsonString(mapMessage));
+
+ TestMap emptyMap = TestMap.getDefaultInstance();
+ assertEquals("{\n}", toSortedJsonString(emptyMap));
+ }
}
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
index f5e1b6b..1618210 100644
--- a/js/binary/proto_test.js
+++ b/js/binary/proto_test.js
@@ -659,5 +659,6 @@
'jspb.test.TestAllTypes');
checkAllFields(msg, msg2);
+
});
});
diff --git a/js/debug.js b/js/debug.js
index ba51bbe..9655b2e 100644
--- a/js/debug.js
+++ b/js/debug.js
@@ -37,6 +37,7 @@
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
+goog.require('jspb.Map');
goog.require('jspb.Message');
@@ -90,6 +91,16 @@
goog.asserts.assertArray(thing);
return goog.array.map(thing, jspb.debug.dump_);
}
+
+ if (message instanceof jspb.Map) {
+ var mapObject = {};
+ var entries = message.entries();
+ for (var entry = entries.next(); !entry.done; entry = entries.next()) {
+ mapObject[entry.value[0]] = jspb.debug.dump_(entry.value[1]);
+ }
+ return mapObject;
+ }
+
goog.asserts.assert(message instanceof jspb.Message,
'Only messages expected: ' + thing);
var ctor = message.constructor;
diff --git a/js/debug_test.js b/js/debug_test.js
index d0d646a..5096869 100644
--- a/js/debug_test.js
+++ b/js/debug_test.js
@@ -38,7 +38,9 @@
// CommonJS-LoadFromFile: test_pb
goog.require('proto.jspb.test.HasExtensions');
goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.MapValueMessageNoBinary');
goog.require('proto.jspb.test.Simple1');
+goog.require('proto.jspb.test.TestMapFieldsNoBinary');
// CommonJS-LoadFromFile: testbinary_pb
@@ -113,4 +115,74 @@
}, jspb.debug.dump(extendable));
});
+ it('testMapsBasicTypes', function() {
+ if (COMPILED) {
+ return;
+ }
+
+ var message = new proto.jspb.test.TestMapFieldsNoBinary();
+ message.getMapBoolStringMap().set(true, 'bool_string_value1');
+ message.getMapBoolStringMap().set(false, 'bool_string_value2');
+ message.getMapStringInt32Map().set('key', 111);
+
+ assertObjectEquals({
+ '$name': 'proto.jspb.test.TestMapFieldsNoBinary',
+ 'mapBoolStringMap': {
+ true: 'bool_string_value1',
+ false: 'bool_string_value2'
+ },
+ 'mapInt32StringMap': {},
+ 'mapInt64StringMap': {},
+ 'mapStringBoolMap': {},
+ 'mapStringDoubleMap': {},
+ 'mapStringEnumMap': {},
+ 'mapStringInt32Map': {
+ 'key': 111
+ },
+ 'mapStringInt64Map': {},
+ 'mapStringMsgMap': {},
+ 'mapStringStringMap': {},
+ 'mapStringTestmapfieldsMap': {}
+ }, jspb.debug.dump(message));
+ });
+
+ it('testMapsMessageValues', function() {
+ if (COMPILED) {
+ return;
+ }
+
+ var value1 = new proto.jspb.test.MapValueMessageNoBinary();
+ value1.setFoo(1111);
+ var value2 = new proto.jspb.test.MapValueMessageNoBinary();
+ value2.setFoo(2222);
+
+ var message = new proto.jspb.test.TestMapFieldsNoBinary();
+ message.getMapStringMsgMap().set('key1', value1);
+ message.getMapStringMsgMap().set('key2', value2);
+
+ assertObjectEquals({
+ '$name': 'proto.jspb.test.TestMapFieldsNoBinary',
+ 'mapBoolStringMap': {},
+ 'mapInt32StringMap': {},
+ 'mapInt64StringMap': {},
+ 'mapStringBoolMap': {},
+ 'mapStringDoubleMap': {},
+ 'mapStringEnumMap': {},
+ 'mapStringInt32Map': {},
+ 'mapStringInt64Map': {},
+ 'mapStringMsgMap': {
+ 'key1': {
+ '$name': 'proto.jspb.test.MapValueMessageNoBinary',
+ 'foo': 1111
+ },
+ 'key2': {
+ '$name': 'proto.jspb.test.MapValueMessageNoBinary',
+ 'foo': 2222
+ }
+ },
+ 'mapStringStringMap': {},
+ 'mapStringTestmapfieldsMap': {}
+ }, jspb.debug.dump(message));
+ });
+
});
diff --git a/js/gulpfile.js b/js/gulpfile.js
index 709c5cf..c458da6 100644
--- a/js/gulpfile.js
+++ b/js/gulpfile.js
@@ -29,6 +29,11 @@
'test5.proto',
'commonjs/test6/test6.proto',
'test8.proto',
+ 'test11.proto',
+ 'test12.proto',
+ 'test13.proto',
+ 'test14.proto',
+ 'test15.proto',
'testbinary.proto',
'testempty.proto',
'test.proto',
diff --git a/js/maps_test.js b/js/maps_test.js
index e496f44..4640c98 100755
--- a/js/maps_test.js
+++ b/js/maps_test.js
@@ -340,11 +340,17 @@
assertElementsEquals(entryIterator.next().value, ['key2', 'value2']);
assertEquals(entryIterator.next().done, true);
- if (typeof(Symbol) != 'undefined') {
+ try {
var entryIterable = m.entries()[Symbol.iterator]();
assertElementsEquals(entryIterable.next().value, ['key1', 'value1']);
assertElementsEquals(entryIterable.next().value, ['key2', 'value2']);
assertEquals(entryIterable.next().done, true);
+ } catch (err) {
+ // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+ // undefined in some environment.
+ if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+ throw err;
+ }
}
var keyIterator = m.keys();
@@ -352,22 +358,34 @@
assertEquals(keyIterator.next().value, 'key2');
assertEquals(keyIterator.next().done, true);
- if (typeof(Symbol) != 'undefined') {
+ try {
var keyIterable = m.keys()[Symbol.iterator]();
assertEquals(keyIterable.next().value, 'key1');
assertEquals(keyIterable.next().value, 'key2');
assertEquals(keyIterable.next().done, true);
+ } catch (err) {
+ // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+ // undefined in some environment.
+ if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+ throw err;
+ }
}
var valueIterator = m.values();
assertEquals(valueIterator.next().value, 'value1');
assertEquals(valueIterator.next().value, 'value2');
assertEquals(valueIterator.next().done, true);
- if (typeof(Symbol) != 'undefined') {
+ try {
var valueIterable = m.values()[Symbol.iterator]();
assertEquals(valueIterable.next().value, 'value1');
assertEquals(valueIterable.next().value, 'value2');
assertEquals(valueIterable.next().done, true);
+ } catch (err) {
+ // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+ // undefined in some environment.
+ if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+ throw err;
+ }
}
});
}
diff --git a/js/message.js b/js/message.js
index 6a37745..17b562e 100644
--- a/js/message.js
+++ b/js/message.js
@@ -427,6 +427,24 @@
goog.isArray(o);
};
+/**
+ * Returns true if the provided argument is an extension object.
+ * @param {*} o The object to classify as array or not.
+ * @return {boolean} True if the provided object is an extension object.
+ * @private
+ */
+jspb.Message.isExtensionObject_ = function(o) {
+ // Normal fields are never objects, so we can be sure that if we find an
+ // object here, then it's the extension object. However, we must ensure that
+ // the object is not an array, since arrays are valid field values (bytes
+ // fields can also be array).
+ // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
+ // in Safari on iOS 8. See the description of CL/86511464 for details.
+ return (o !== null && typeof o == 'object' &&
+ !jspb.Message.isArray_(o) &&
+ !(jspb.Message.SUPPORTS_UINT8ARRAY_ && o instanceof Uint8Array));
+};
+
/**
* If the array contains an extension object in its last position, then the
@@ -452,13 +470,7 @@
if (msgLength) {
lastIndex = msgLength - 1;
var obj = msg.array[lastIndex];
- // Normal fields are never objects, so we can be sure that if we find an
- // object here, then it's the extension object. However, we must ensure that
- // the object is not an array, since arrays are valid field values.
- // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
- // in Safari on iOS 8. See the description of CL/86511464 for details.
- if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
- !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
+ if (jspb.Message.isExtensionObject_(obj)) {
msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
msg.extensionObject_ = obj;
return;
diff --git a/js/message_test.js b/js/message_test.js
index 2bfec62..c237d06 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -33,7 +33,6 @@
goog.setTestOnly();
goog.require('goog.json');
-goog.require('goog.string');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.asserts');
goog.require('goog.userAgent');
@@ -41,6 +40,38 @@
// CommonJS-LoadFromFile: google-protobuf jspb
goog.require('jspb.Message');
+// CommonJS-LoadFromFile: test15_pb proto.jspb.filenametest.package1
+goog.require('proto.jspb.filenametest.package1.b');
+
+// CommonJS-LoadFromFile: test14_pb proto.jspb.filenametest.package2
+goog.require('proto.jspb.filenametest.package2.TestMessage');
+
+// CommonJS-LoadFromFile: test13_pb proto.jspb.filenametest.package1
+goog.require('proto.jspb.filenametest.package1.a');
+goog.require('proto.jspb.filenametest.package1.TestMessage');
+
+// CommonJS-LoadFromFile: test12_pb proto.jspb.circulartest
+goog.require('proto.jspb.circulartest.ExtensionContainingType1');
+goog.require('proto.jspb.circulartest.ExtensionContainingType2');
+goog.require('proto.jspb.circulartest.ExtensionField1');
+goog.require('proto.jspb.circulartest.ExtensionField2');
+goog.require('proto.jspb.circulartest.ExtensionField3');
+goog.require('proto.jspb.circulartest.MapField1');
+goog.require('proto.jspb.circulartest.MapField2');
+goog.require('proto.jspb.circulartest.MessageField1');
+goog.require('proto.jspb.circulartest.MessageField2');
+goog.require('proto.jspb.circulartest.NestedEnum1');
+goog.require('proto.jspb.circulartest.NestedEnum2');
+goog.require('proto.jspb.circulartest.NestedMessage1');
+goog.require('proto.jspb.circulartest.NestedMessage2');
+goog.require('proto.jspb.circulartest.RepeatedMessageField1');
+goog.require('proto.jspb.circulartest.RepeatedMessageField2');
+
+// CommonJS-LoadFromFile: test11_pb proto.jspb.exttest.reverse
+goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1');
+goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2');
+goog.require('proto.jspb.exttest.reverse.c');
+
// CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested
goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage');
goog.require('proto.jspb.exttest.nested.TestOuterMessage');
@@ -77,6 +108,7 @@
goog.require('proto.jspb.test.TestEndsWithBytes');
goog.require('proto.jspb.test.TestGroup');
goog.require('proto.jspb.test.TestGroup1');
+goog.require('proto.jspb.test.TestLastFieldBeforePivot');
goog.require('proto.jspb.test.TestMessageWithOneof');
goog.require('proto.jspb.test.TestReservedNames');
goog.require('proto.jspb.test.TestReservedNamesExtension');
@@ -284,42 +316,6 @@
assertFalse(response.hasEnumField());
});
- it('testClearFields', function() {
- var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
- var foo = new proto.jspb.test.OptionalFields(data);
- foo.clearAString();
- foo.clearABool();
- foo.clearANestedMessage();
- foo.clearARepeatedMessageList();
- foo.clearARepeatedStringList();
- assertEquals('', foo.getAString());
- assertEquals(false, foo.getABool());
- assertUndefined(foo.getANestedMessage());
- assertFalse(foo.hasAString());
- assertFalse(foo.hasABool());
- assertObjectEquals([], foo.getARepeatedMessageList());
- assertObjectEquals([], foo.getARepeatedStringList());
- // NOTE: We want the missing fields in 'expected' to be undefined,
- // but we actually get a sparse array instead. We could use something
- // like [1,undefined,2] to avoid this, except that this is still
- // sparse on IE. No comment...
- var expected = [,,, [], []];
- expected[0] = expected[1] = expected[2] = undefined;
- assertObjectEquals(expected, foo.toArray());
- });
-
- it('testDifferenceRawObject', /** @suppress {visibility} */ function() {
- var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
- var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
- {1000: 'unique'}]);
- var diff = /** @type {proto.jspb.test.HasExtensions} */
- (jspb.Message.difference(p1, p2));
- assertEquals('', diff.getStr1());
- assertEquals('what', diff.getStr2());
- assertEquals('', diff.getStr3());
- assertEquals('unique', diff.extensionObject_[1000]);
- });
-
it('testEqualsSimple', function() {
var s1 = new proto.jspb.test.Simple1(['hi']);
assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
@@ -419,6 +415,12 @@
['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
});
+ it('testInitializeMessageWithLastFieldNull', function() {
+ // This tests for regression to bug http://b/117298778
+ var msg = new proto.jspb.test.TestLastFieldBeforePivot([null]);
+ assertNotUndefined(msg.getLastFieldBeforePivot());
+ });
+
it('testEqualsNonFinite', function() {
assertTrue(jspb.Message.compareFields(NaN, NaN));
assertTrue(jspb.Message.compareFields(NaN, 'NaN'));
@@ -787,71 +789,6 @@
message.getRecursiveOneofCase());
});
- it('testInitializeMessageWithSingleValueSetInOneof', function() {
- var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
-
- assertEquals('x', message.getPone());
- assertEquals('', message.getPthree());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
- message.getPartialOneofCase());
- });
-
- it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
- var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
-
- assertEquals('', message.getPone());
- assertEquals('y', message.getPthree());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
- message.getPartialOneofCase());
- });
-
- it('testSettingOneofFieldClearsOthers', function() {
- var message = new proto.jspb.test.TestMessageWithOneof;
- assertEquals('', message.getPone());
- assertEquals('', message.getPthree());
- assertFalse(message.hasPone());
- assertFalse(message.hasPthree());
-
- message.setPone('hi');
- assertEquals('hi', message.getPone());
- assertEquals('', message.getPthree());
- assertTrue(message.hasPone());
- assertFalse(message.hasPthree());
-
- message.setPthree('bye');
- assertEquals('', message.getPone());
- assertEquals('bye', message.getPthree());
- assertFalse(message.hasPone());
- assertTrue(message.hasPthree());
- });
-
- it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
- var other = new proto.jspb.test.TestMessageWithOneof;
- var message = new proto.jspb.test.TestMessageWithOneof;
- assertEquals('', message.getPone());
- assertEquals('', message.getPthree());
- assertUndefined(message.getRone());
- assertFalse(message.hasPone());
- assertFalse(message.hasPthree());
-
- message.setPone('hi');
- message.setRone(other);
- assertEquals('hi', message.getPone());
- assertEquals('', message.getPthree());
- assertEquals(other, message.getRone());
- assertTrue(message.hasPone());
- assertFalse(message.hasPthree());
-
- message.setPthree('bye');
- assertEquals('', message.getPone());
- assertEquals('bye', message.getPthree());
- assertEquals(other, message.getRone());
- assertFalse(message.hasPone());
- assertTrue(message.hasPthree());
- });
-
it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
var message = new proto.jspb.test.TestMessageWithOneof;
assertEquals(
@@ -871,178 +808,6 @@
message.getPartialOneofCase());
});
- it('testMessageWithDefaultOneofValues', function() {
- var message = new proto.jspb.test.TestMessageWithOneof;
- assertEquals(1234, message.getAone());
- assertEquals(0, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
- .DEFAULT_ONEOF_A_NOT_SET,
- message.getDefaultOneofACase());
-
- message.setAone(567);
- assertEquals(567, message.getAone());
- assertEquals(0, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
- message.getDefaultOneofACase());
-
- message.setAtwo(890);
- assertEquals(1234, message.getAone());
- assertEquals(890, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
- message.getDefaultOneofACase());
-
- message.clearAtwo();
- assertEquals(1234, message.getAone());
- assertEquals(0, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
- .DEFAULT_ONEOF_A_NOT_SET,
- message.getDefaultOneofACase());
- });
-
- it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
- var message = new proto.jspb.test.TestMessageWithOneof;
- assertEquals(0, message.getBone());
- assertEquals(1234, message.getBtwo());
- assertFalse(message.hasBone());
- assertFalse(message.hasBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
- .DEFAULT_ONEOF_B_NOT_SET,
- message.getDefaultOneofBCase());
-
- message.setBone(2);
- assertEquals(2, message.getBone());
- assertEquals(1234, message.getBtwo());
- assertTrue(message.hasBone());
- assertFalse(message.hasBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
- message.getDefaultOneofBCase());
-
- message.setBtwo(3);
- assertEquals(0, message.getBone());
- assertFalse(message.hasBone());
- assertTrue(message.hasBtwo());
- assertEquals(3, message.getBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
- message.getDefaultOneofBCase());
-
- message.clearBtwo();
- assertEquals(0, message.getBone());
- assertFalse(message.hasBone());
- assertFalse(message.hasBtwo());
- assertEquals(1234, message.getBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
- .DEFAULT_ONEOF_B_NOT_SET,
- message.getDefaultOneofBCase());
- });
-
- it('testInitializeMessageWithOneofDefaults', function() {
- var message =
- new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567));
- assertEquals(567, message.getAone());
- assertEquals(0, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
- message.getDefaultOneofACase());
-
- message =
- new proto.jspb.test.TestMessageWithOneof(new Array(10).concat(890));
- assertEquals(1234, message.getAone());
- assertEquals(890, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
- message.getDefaultOneofACase());
-
- message =
- new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567, 890));
- assertEquals(1234, message.getAone());
- assertEquals(890, message.getAtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
- message.getDefaultOneofACase());
- });
-
- it('testInitializeMessageWithOneofDefaults_defaultNotSetOnFirstField',
- function() {
- var message;
-
- message =
- new proto.jspb.test.TestMessageWithOneof(new Array(11).concat(567));
- assertEquals(567, message.getBone());
- assertEquals(1234, message.getBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
- message.getDefaultOneofBCase());
-
- message =
- new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890));
- assertEquals(0, message.getBone());
- assertEquals(890, message.getBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
- message.getDefaultOneofBCase());
-
- message = new proto.jspb.test.TestMessageWithOneof(
- new Array(11).concat(567, 890));
- assertEquals(0, message.getBone());
- assertEquals(890, message.getBtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
- message.getDefaultOneofBCase());
- });
-
- it('testOneofContainingAnotherMessage', function() {
- var message = new proto.jspb.test.TestMessageWithOneof;
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
- RECURSIVE_ONEOF_NOT_SET,
- message.getRecursiveOneofCase());
-
- var other = new proto.jspb.test.TestMessageWithOneof;
- message.setRone(other);
- assertEquals(other, message.getRone());
- assertEquals('', message.getRtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
- message.getRecursiveOneofCase());
-
- message.setRtwo('hi');
- assertUndefined(message.getRone());
- assertEquals('hi', message.getRtwo());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RTWO,
- message.getRecursiveOneofCase());
- });
-
- it('testQueryingOneofCaseEnsuresOnlyOneFieldIsSetInUnderlyingArray',
- function() {
- var message = new proto.jspb.test.TestMessageWithOneof;
- message.setPone('x');
- assertEquals('x', message.getPone());
- assertEquals('', message.getPthree());
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
- message.getPartialOneofCase());
-
- var array = message.toArray();
- assertEquals('x', array[2]);
- assertUndefined(array[4]);
- array[4] = 'y';
-
- assertEquals(
- proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
- message.getPartialOneofCase());
- assertUndefined(array[2]);
- assertEquals('y', array[4]);
- });
-
it('testFloatingPointFieldsSupportNan', function() {
var assertNan = function(x) {
assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
@@ -1065,4 +830,170 @@
assertNan(message.getDefaultDoubleField());
});
+ it('testExtensionReverseOrder', function() {
+ var message2 =
+ new proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2;
+
+ message2.setExtension(
+ proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a, 233);
+ message2.setExtension(
+ proto
+ .jspb
+ .exttest
+ .reverse
+ .TestExtensionReverseOrderMessage1
+ .TestExtensionReverseOrderNestedMessage1.b, 2333);
+ message2.setExtension(proto.jspb.exttest.reverse.c, 23333);
+
+ assertEquals(
+ 233,
+ message2.getExtension(
+ proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a));
+ assertEquals(
+ 2333,
+ message2.getExtension(
+ proto
+ .jspb
+ .exttest
+ .reverse
+ .TestExtensionReverseOrderMessage1
+ .TestExtensionReverseOrderNestedMessage1.b));
+ assertEquals(
+ 23333,
+ message2.getExtension(proto.jspb.exttest.reverse.c));
+ });
+
+ it('testCircularDepsBaseOnMessageField', function() {
+ var nestMessage1 = new proto.jspb.circulartest.MessageField1;
+ var nestMessage2 = new proto.jspb.circulartest.MessageField2;
+ var message1 = new proto.jspb.circulartest.MessageField1;
+ var message2 = new proto.jspb.circulartest.MessageField2;
+
+ nestMessage1.setA(1);
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message2.setB(nestMessage1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(1, message2.getB().getA());
+ });
+
+
+ it('testCircularDepsBaseOnRepeatedMessageField', function() {
+ var nestMessage1 = new proto.jspb.circulartest.RepeatedMessageField1;
+ var nestMessage2 = new proto.jspb.circulartest.RepeatedMessageField2;
+ var message1 = new proto.jspb.circulartest.RepeatedMessageField1;
+ var message2 = new proto.jspb.circulartest.RepeatedMessageField2;
+
+ nestMessage1.setA(1);
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message2.addB(nestMessage1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(1, message2.getBList()[0].getA());
+ });
+
+ it('testCircularDepsBaseOnMapField', function() {
+ var nestMessage1 = new proto.jspb.circulartest.MapField1;
+ var nestMessage2 = new proto.jspb.circulartest.MapField2;
+ var message1 = new proto.jspb.circulartest.MapField1;
+ var message2 = new proto.jspb.circulartest.MapField2;
+
+ nestMessage1.setA(1);
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message2.getBMap().set(1, nestMessage1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(1, message2.getBMap().get(1).getA());
+ });
+
+ it('testCircularDepsBaseOnNestedMessage', function() {
+ var nestMessage1 =
+ new proto.jspb.circulartest.NestedMessage1.NestedNestedMessage;
+ var nestMessage2 = new proto.jspb.circulartest.NestedMessage2;
+ var message1 = new proto.jspb.circulartest.NestedMessage1;
+ var message2 = new proto.jspb.circulartest.NestedMessage2;
+
+ nestMessage1.setA(1);
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message2.setB(nestMessage1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(1, message2.getB().getA());
+ });
+
+ it('testCircularDepsBaseOnNestedEnum', function() {
+ var nestMessage2 = new proto.jspb.circulartest.NestedEnum2;
+ var message1 = new proto.jspb.circulartest.NestedEnum1;
+ var message2 = new proto.jspb.circulartest.NestedEnum2;
+
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message2.setB(proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(
+ proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1,
+ message2.getB());
+ });
+
+ it('testCircularDepsBaseOnExtensionContainingType', function() {
+ var nestMessage2 = new proto.jspb.circulartest.ExtensionContainingType2;
+ var message1 = new proto.jspb.circulartest.ExtensionContainingType1;
+
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message1.setExtension(
+ proto.jspb.circulartest.ExtensionContainingType2.c, 1);
+
+
+ assertEquals(2, message1.getB().getA());
+ assertEquals(
+ 1,
+ message1.getExtension(
+ proto.jspb.circulartest.ExtensionContainingType2.c));
+ });
+
+ it('testCircularDepsBaseOnExtensionField', function() {
+ var nestMessage2 = new proto.jspb.circulartest.ExtensionField2;
+ var message1 = new proto.jspb.circulartest.ExtensionField1;
+ var message3 = new proto.jspb.circulartest.ExtensionField3;
+
+ nestMessage2.setA(2);
+ message1.setB(nestMessage2);
+ message3.setExtension(proto.jspb.circulartest.ExtensionField2.c, message1);
+
+
+ assertEquals(
+ 2,
+ message3.getExtension(proto.jspb.circulartest.ExtensionField2.c)
+ .getB()
+ .getA());
+ });
+
+ it('testSameMessageNameOuputs', function() {
+ var package1Message = new proto.jspb.filenametest.package1.TestMessage;
+ var package2Message = new proto.jspb.filenametest.package2.TestMessage;
+
+ package1Message.setExtension(
+ proto.jspb.filenametest.package1.a, 10);
+ package1Message.setExtension(
+ proto.jspb.filenametest.package1.b, 11);
+ package2Message.setA(12);
+
+ assertEquals(10,
+ package1Message.getExtension(proto.jspb.filenametest.package1.a));
+ assertEquals(11,
+ package1Message.getExtension(proto.jspb.filenametest.package1.b));
+ assertEquals(12, package2Message.getA());
+ });
+
});
diff --git a/js/proto3_test.js b/js/proto3_test.js
index 4aed88b..7f9d71d 100644
--- a/js/proto3_test.js
+++ b/js/proto3_test.js
@@ -30,17 +30,15 @@
goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts');
-
// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.ForeignMessage');
-
// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
goog.require('proto.jspb.test.Proto3Enum');
goog.require('proto.jspb.test.TestProto3');
-
+// CommonJS-LoadFromFile: google/protobuf/any_pb proto.google.protobuf
+goog.require('proto.google.protobuf.Any');
// CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf
goog.require('proto.google.protobuf.Timestamp');
-
// CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf
goog.require('proto.google.protobuf.Struct');
@@ -377,6 +375,7 @@
});
+
it('testTimestampWellKnownType', function() {
var msg = new proto.google.protobuf.Timestamp();
msg.fromDate(new Date(123456789));
@@ -384,6 +383,9 @@
assertEquals(789000000, msg.getNanos());
var date = msg.toDate();
assertEquals(123456789, date.getTime());
+ var anotherMsg = proto.google.protobuf.Timestamp.fromDate(date);
+ assertEquals(msg.getSeconds(), anotherMsg.getSeconds());
+ assertEquals(msg.getNanos(), anotherMsg.getNanos());
});
it('testStructWellKnownType', function() {
diff --git a/js/test.proto b/js/test.proto
index 3b538b5..454fd83 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -241,6 +241,17 @@
optional bytes data = 2;
}
+// This message is for testing extension handling doesn't affect fields before
+// pivot. Don't add new field to this message. See b/117298778 for more detail.
+message TestLastFieldBeforePivot {
+ optional int32 last_field_before_pivot = 1;
+ extensions 100 to max;
+}
+
+extend TestLastFieldBeforePivot {
+ optional int32 extend_test_last_field_before_pivot_field = 101;
+}
+
message Int64Types {
optional int64 int64_normal = 1 [jstype=JS_NORMAL];
diff --git a/js/test11.proto b/js/test11.proto
new file mode 100644
index 0000000..ae65a46
--- /dev/null
+++ b/js/test11.proto
@@ -0,0 +1,52 @@
+// 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.
+
+syntax = "proto2";
+
+package jspb.exttest.reverse;
+
+message TestExtensionReverseOrderMessage1 {
+ extend TestExtensionReverseOrderMessage2 {
+ optional int32 a = 1;
+ }
+ message TestExtensionReverseOrderNestedMessage1 {
+ extend TestExtensionReverseOrderMessage2 {
+ optional int32 b = 2;
+ }
+ }
+}
+
+extend TestExtensionReverseOrderMessage2 {
+ optional int32 c = 3;
+}
+
+message TestExtensionReverseOrderMessage2 {
+ extensions 1 to 100;
+}
diff --git a/js/test12.proto b/js/test12.proto
new file mode 100644
index 0000000..4ece1d0
--- /dev/null
+++ b/js/test12.proto
@@ -0,0 +1,119 @@
+// 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.
+
+syntax = "proto2";
+
+
+package jspb.circulartest;
+
+message MessageField1 {
+ optional int32 a = 1;
+ optional MessageField2 b = 2;
+}
+
+message MessageField2 {
+ optional int32 a = 1;
+ optional MessageField1 b = 2;
+}
+
+
+message RepeatedMessageField1 {
+ optional int32 a = 1;
+ optional RepeatedMessageField2 b = 2;
+}
+
+message RepeatedMessageField2 {
+ optional int32 a = 1;
+ repeated RepeatedMessageField1 b = 2;
+}
+
+message MapField1 {
+ optional int32 a = 1;
+ optional MapField2 b = 2;
+}
+
+message MapField2 {
+ optional int32 a = 1;
+ map<int32, MapField1> b = 2;
+}
+
+message NestedMessage1 {
+ optional NestedMessage2 b = 2;
+ message NestedNestedMessage {
+ optional int32 a = 1;
+ }
+}
+
+message NestedMessage2 {
+ optional int32 a = 1;
+ optional NestedMessage1.NestedNestedMessage b = 2;
+}
+
+message NestedEnum1 {
+ optional NestedEnum2 b = 2;
+ enum NestedNestedEnum {
+ UNDEFINED = 0;
+ VALUE_1 = 1;
+ }
+}
+
+message NestedEnum2 {
+ optional int32 a = 1;
+ optional NestedEnum1.NestedNestedEnum b = 2;
+}
+
+message ExtensionContainingType1 {
+ optional int32 a = 1;
+ optional ExtensionContainingType2 b = 2;
+ extensions 99 to 100;
+}
+
+message ExtensionContainingType2 {
+ optional int32 a = 1;
+ extend ExtensionContainingType1 {
+ optional int32 c = 99;
+ }
+}
+
+message ExtensionField1 {
+ optional int32 a = 1;
+ optional ExtensionField2 b = 2;
+}
+
+message ExtensionField2 {
+ optional int32 a = 1;
+ extend ExtensionField3 {
+ optional ExtensionField1 c = 99;
+ }
+}
+
+message ExtensionField3 {
+ extensions 99 to 100;
+}
diff --git a/js/test13.proto b/js/test13.proto
new file mode 100644
index 0000000..4f9d272
--- /dev/null
+++ b/js/test13.proto
@@ -0,0 +1,70 @@
+// 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.
+
+syntax = "proto2";
+
+package jspb.filenametest.package1;
+
+message TestMessage {
+ extensions 1 to 100;
+}
+
+extend TestMessage {
+ optional int32 a = 1;
+}
+
+enum TestEnum {
+ VALUE_0 = 0;
+ VALUE_1 = 1;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1 {
+ optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2
+ a = 1;
+ optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2 {
+ optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3
+ a = 1;
+ optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3 {
+ optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4
+ a = 1;
+ optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4 {
+ optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1
+ a = 1;
+ optional int32 b = 2;
+}
diff --git a/js/test14.proto b/js/test14.proto
new file mode 100644
index 0000000..2447eb1
--- /dev/null
+++ b/js/test14.proto
@@ -0,0 +1,43 @@
+// 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.
+
+syntax = "proto2";
+
+package jspb.filenametest.package2;
+
+message TestMessage {
+ optional int32 a = 1;
+}
+
+enum TestEnum {
+ VALUE_0 = 0;
+ VALUE_1 = 1;
+ VALUE_2 = 2;
+}
diff --git a/js/test15.proto b/js/test15.proto
new file mode 100644
index 0000000..602cc2d
--- /dev/null
+++ b/js/test15.proto
@@ -0,0 +1,39 @@
+// 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.
+
+syntax = "proto2";
+
+import "test13.proto";
+
+package jspb.filenametest.package1;
+
+extend TestMessage {
+ optional int32 b = 2;
+}
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index 19ca686..f6ea25c 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -129,7 +129,7 @@
* 01:30 UTC on January 15, 2017.
*
* In JavaScript, one can convert a Date object to this format using the
- * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+ * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
* method. In Python, a standard `datetime.datetime` object can be converted
* to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
* with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto.php b/php/src/Google/Protobuf/Internal/DescriptorProto.php
index 3b215d5..40ea19a 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a message type.
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
index c06a0a6..85d0f28 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.DescriptorProto.ExtensionRange</code>
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php b/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
index 73c964f..e3c6e54 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Range of reserved tag numbers. Reserved tag numbers may not be used by
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
index da30fa9..25f4933 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes an enum type.
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php b/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
index e107958..d84e2af 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Range of reserved numeric values. Reserved values may not be used by
diff --git a/php/src/Google/Protobuf/Internal/EnumOptions.php b/php/src/Google/Protobuf/Internal/EnumOptions.php
index 3d74c81..6af31af 100644
--- a/php/src/Google/Protobuf/Internal/EnumOptions.php
+++ b/php/src/Google/Protobuf/Internal/EnumOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.EnumOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
index 50bda00..8601c2b 100644
--- a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a value within an enum.
diff --git a/php/src/Google/Protobuf/Internal/EnumValueOptions.php b/php/src/Google/Protobuf/Internal/EnumValueOptions.php
index a267c6d..d1f5edd 100644
--- a/php/src/Google/Protobuf/Internal/EnumValueOptions.php
+++ b/php/src/Google/Protobuf/Internal/EnumValueOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.EnumValueOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php b/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
index 00fbebe..caeb802 100644
--- a/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
+++ b/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.ExtensionRangeOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
index e578197..1dd6523 100644
--- a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a field within a message.
diff --git a/php/src/Google/Protobuf/Internal/FieldOptions.php b/php/src/Google/Protobuf/Internal/FieldOptions.php
index 751c278..c709564 100644
--- a/php/src/Google/Protobuf/Internal/FieldOptions.php
+++ b/php/src/Google/Protobuf/Internal/FieldOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.FieldOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
index cb10aa7..8eee320 100644
--- a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a complete .proto file.
diff --git a/php/src/Google/Protobuf/Internal/FileDescriptorSet.php b/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
index 9907b17..b5cc1f1 100644
--- a/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
+++ b/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* The protocol compiler can output a FileDescriptorSet containing the .proto
diff --git a/php/src/Google/Protobuf/Internal/FileOptions.php b/php/src/Google/Protobuf/Internal/FileOptions.php
index c6b36bb..c606496 100644
--- a/php/src/Google/Protobuf/Internal/FileOptions.php
+++ b/php/src/Google/Protobuf/Internal/FileOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.FileOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
index f5a65be..2d6fe00 100644
--- a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
+++ b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes the relationship between generated code and its original source
diff --git a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
index 09f958d..74e089c 100644
--- a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
+++ b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.GeneratedCodeInfo.Annotation</code>
diff --git a/php/src/Google/Protobuf/Internal/MessageOptions.php b/php/src/Google/Protobuf/Internal/MessageOptions.php
index bf490de..ccf0919 100644
--- a/php/src/Google/Protobuf/Internal/MessageOptions.php
+++ b/php/src/Google/Protobuf/Internal/MessageOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.MessageOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
index 1bd5dd3..fba0c99 100644
--- a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a method of a service.
diff --git a/php/src/Google/Protobuf/Internal/MethodOptions.php b/php/src/Google/Protobuf/Internal/MethodOptions.php
index a2c729a..21c07f5 100644
--- a/php/src/Google/Protobuf/Internal/MethodOptions.php
+++ b/php/src/Google/Protobuf/Internal/MethodOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.MethodOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
index 9ecfe5c..c471c80 100644
--- a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a oneof.
diff --git a/php/src/Google/Protobuf/Internal/OneofOptions.php b/php/src/Google/Protobuf/Internal/OneofOptions.php
index 46b516f..dab1db4 100644
--- a/php/src/Google/Protobuf/Internal/OneofOptions.php
+++ b/php/src/Google/Protobuf/Internal/OneofOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.OneofOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
index 8de7afd..a717371 100644
--- a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Describes a service.
diff --git a/php/src/Google/Protobuf/Internal/ServiceOptions.php b/php/src/Google/Protobuf/Internal/ServiceOptions.php
index 67162f3..d59d9c3 100644
--- a/php/src/Google/Protobuf/Internal/ServiceOptions.php
+++ b/php/src/Google/Protobuf/Internal/ServiceOptions.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.ServiceOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/SourceCodeInfo.php b/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
index 6e413f7..75cc3dd 100644
--- a/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
+++ b/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Encapsulates information about the original source file from which a
diff --git a/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php b/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
index bad247a..dd39e5b 100644
--- a/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
+++ b/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* Generated from protobuf message <code>google.protobuf.SourceCodeInfo.Location</code>
diff --git a/php/src/Google/Protobuf/Internal/UninterpretedOption.php b/php/src/Google/Protobuf/Internal/UninterpretedOption.php
index 3b517ec..2a13d98 100644
--- a/php/src/Google/Protobuf/Internal/UninterpretedOption.php
+++ b/php/src/Google/Protobuf/Internal/UninterpretedOption.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* A message representing a option the parser does not recognize. This only
diff --git a/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php b/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
index 92ee4b4..f40c485 100644
--- a/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
+++ b/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
@@ -9,6 +9,7 @@
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
/**
* The name of the uninterpreted option. Each string represents a segment in
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index ef96196..b82936b 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -41,12 +41,12 @@
__author__ = 'petar@google.com (Petar Petrov)'
-try:
- # This fallback applies for all versions of Python before 3.3
- import collections.abc as collections_abc
-except ImportError:
- import collections as collections_abc
import sys
+try:
+ # This fallback applies for all versions of Python before 3.3
+ import collections.abc as collections_abc
+except ImportError:
+ import collections as collections_abc
if sys.version_info[0] < 3:
# We would use collections_abc.MutableMapping all the time, but in Python 2
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 1b72b0b..3244251 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -529,10 +529,6 @@
conflict_fd = copy.deepcopy(unittest_fd)
conflict_fd.name = 'other_file'
if api_implementation.Type() == 'cpp':
- try:
- self.pool.Add(unittest_fd)
- self.pool.Add(conflict_fd)
- except TypeError:
pass
else:
with warnings.catch_warnings(record=True) as w:
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index af6bece..e753cba 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -192,6 +192,14 @@
self.assertTrue(enum_value_descriptor.has_options)
self.assertFalse(other_enum_value_descriptor.has_options)
+ def testCustomOptionsCopyTo(self):
+ message_descriptor = (unittest_custom_options_pb2.
+ TestMessageWithCustomOptions.DESCRIPTOR)
+ message_proto = descriptor_pb2.DescriptorProto()
+ message_descriptor.CopyToProto(message_proto)
+ self.assertEqual(len(message_proto.options.ListFields()),
+ 2)
+
def testDifferentCustomOptionTypes(self):
kint32min = -2**31
kint64min = -2**63
diff --git a/python/google/protobuf/internal/enum_type_wrapper.py b/python/google/protobuf/internal/enum_type_wrapper.py
index 1cffe35..77e4be0 100644
--- a/python/google/protobuf/internal/enum_type_wrapper.py
+++ b/python/google/protobuf/internal/enum_type_wrapper.py
@@ -46,7 +46,7 @@
def __init__(self, enum_type):
"""Inits EnumTypeWrapper with an EnumDescriptor."""
self._enum_type = enum_type
- self.DESCRIPTOR = enum_type;
+ self.DESCRIPTOR = enum_type
def Name(self, number):
"""Returns a string containing the name of an enum value."""
@@ -56,7 +56,7 @@
self._enum_type.name, number))
def Value(self, name):
- """Returns the value coresponding to the given enum name."""
+ """Returns the value corresponding to the given enum name."""
if name in self._enum_type.values_by_name:
return self._enum_type.values_by_name[name].number
raise ValueError('Enum %s has no value defined for name %s' % (
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index bd85ce8..db34c93 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -523,7 +523,8 @@
'}'))
parsed_message = json_format_proto3_pb2.TestStruct()
self.CheckParseBack(message, parsed_message)
- parsed_message.value['empty_struct'] # check for regression; this used to raise
+ # check for regression; this used to raise
+ parsed_message.value['empty_struct']
parsed_message.value['empty_list']
def testValueMessage(self):
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index d733dc8..137420d 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -159,15 +159,6 @@
with self.assertRaises(message.DecodeError) as context:
msg.FromString(end_tag)
self.assertEqual('Unexpected end-group tag.', str(context.exception))
- else:
- with warnings.catch_warnings(record=True) as w:
- # Cause all warnings to always be triggered.
- warnings.simplefilter('always')
- msg.FromString(end_tag)
- assert len(w) == 1
- assert issubclass(w[-1].category, RuntimeWarning)
- self.assertEqual('Unexpected end-group tag: Not all data was converted',
- str(w[-1].message))
def testDeterminismParameters(self, message_module):
# This message is always deterministically serialized, even if determinism
@@ -1791,6 +1782,13 @@
old_map_value = msg2.map_int32_foreign_message[222]
msg2.MergeFrom(msg)
+ # Compare with expected message instead of call
+ # msg2.map_int32_foreign_message[222] to make sure MergeFrom does not
+ # sync with repeated field and there is no duplicated keys.
+ expected_msg = map_unittest_pb2.TestMap()
+ expected_msg.CopyFrom(msg)
+ expected_msg.map_int64_int64[88] = 99
+ self.assertEqual(msg2, expected_msg)
self.assertEqual(34, msg2.map_int32_int32[12])
self.assertEqual(78, msg2.map_int32_int32[56])
@@ -1854,9 +1852,13 @@
self.assertEqual(99, msg2.map_int64_int64[88])
msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message)
- self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
- self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
- self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
+ # Compare with expected message instead of call
+ # msg.map_int32_foreign_message[222] to make sure MergeFrom does not
+ # sync with repeated field and no duplicated keys.
+ expected_msg = map_unittest_pb2.TestMap()
+ expected_msg.CopyFrom(msg)
+ expected_msg.map_int64_int64[88] = 99
+ self.assertEqual(msg2, expected_msg)
# Test when cpp extension cache a map.
m1 = map_unittest_pb2.TestMap()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 4e0f545..f77c44b 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -294,7 +294,7 @@
def _IsMessageMapField(field):
- value_type = field.message_type.fields_by_name["value"]
+ value_type = field.message_type.fields_by_name['value']
return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
@@ -311,12 +311,12 @@
wire_format.IsTypePackable(field_descriptor.type))
if not is_packable:
is_packed = False
- elif field_descriptor.containing_type.syntax == "proto2":
+ elif field_descriptor.containing_type.syntax == 'proto2':
is_packed = (field_descriptor.has_options and
field_descriptor.GetOptions().packed)
else:
has_packed_false = (field_descriptor.has_options and
- field_descriptor.GetOptions().HasField("packed") and
+ field_descriptor.GetOptions().HasField('packed') and
field_descriptor.GetOptions().packed == False)
is_packed = not has_packed_false
is_map_entry = _IsMapField(field_descriptor)
@@ -529,7 +529,7 @@
for field_name, field_value in kwargs.items():
field = _GetFieldByName(message_descriptor, field_name)
if field is None:
- raise TypeError("%s() got an unexpected keyword argument '%s'" %
+ raise TypeError('%s() got an unexpected keyword argument "%s"' %
(message_descriptor.name, field_name))
if field_value is None:
# field=None is the same as no field at all.
@@ -619,7 +619,7 @@
# handle specially here.
assert _FieldDescriptor.MAX_CPPTYPE == 10
- constant_name = field.name.upper() + "_FIELD_NUMBER"
+ constant_name = field.name.upper() + '_FIELD_NUMBER'
setattr(cls, constant_name, field.number)
if field.label == _FieldDescriptor.LABEL_REPEATED:
@@ -698,7 +698,7 @@
type_checker = type_checkers.GetTypeChecker(field)
default_value = field.default_value
valid_values = set()
- is_proto3 = field.containing_type.syntax == "proto3"
+ is_proto3 = field.containing_type.syntax == 'proto3'
def getter(self):
# TODO(protobuf-team): This may be broken since there may not be
@@ -786,7 +786,7 @@
"""Adds properties for all fields in this protocol message type."""
extension_dict = descriptor.extensions_by_name
for extension_name, extension_field in extension_dict.items():
- constant_name = extension_name.upper() + "_FIELD_NUMBER"
+ constant_name = extension_name.upper() + '_FIELD_NUMBER'
setattr(cls, constant_name, extension_field.number)
# TODO(amauryfa): Migrate all users of these attributes to functions like
@@ -835,14 +835,15 @@
cls.ListFields = ListFields
-_Proto3HasError = 'Protocol message has no non-repeated submessage field "%s"'
-_Proto2HasError = 'Protocol message has no non-repeated field "%s"'
+_PROTO3_ERROR_TEMPLATE = \
+ 'Protocol message %s has no non-repeated submessage field "%s"'
+_PROTO2_ERROR_TEMPLATE = 'Protocol message %s has no non-repeated field "%s"'
def _AddHasFieldMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods()."""
is_proto3 = (message_descriptor.syntax == "proto3")
- error_msg = _Proto3HasError if is_proto3 else _Proto2HasError
+ error_msg = _PROTO3_ERROR_TEMPLATE if is_proto3 else _PROTO2_ERROR_TEMPLATE
hassable_fields = {}
for field in message_descriptor.fields:
@@ -863,7 +864,7 @@
try:
field = hassable_fields[field_name]
except KeyError:
- raise ValueError(error_msg % field_name)
+ raise ValueError(error_msg % (message_descriptor.full_name, field_name))
if isinstance(field, descriptor_mod.OneofDescriptor):
try:
@@ -893,7 +894,7 @@
else:
return
except KeyError:
- raise ValueError('Protocol message %s() has no "%s" field.' %
+ raise ValueError('Protocol message %s has no "%s" field.' %
(message_descriptor.name, field_name))
if field in self._fields:
@@ -1278,7 +1279,7 @@
for field, value in self.ListFields():
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
if field.is_extension:
- name = "(%s)" % field.full_name
+ name = '(%s)' % field.full_name
else:
name = field.name
@@ -1286,7 +1287,7 @@
if _IsMessageMapField(field):
for key in value:
element = value[key]
- prefix = "%s[%s]." % (name, key)
+ prefix = '%s[%s].' % (name, key)
sub_errors = element.FindInitializationErrors()
errors += [prefix + error for error in sub_errors]
else:
@@ -1295,11 +1296,11 @@
elif field.label == _FieldDescriptor.LABEL_REPEATED:
for i in range(len(value)):
element = value[i]
- prefix = "%s[%d]." % (name, i)
+ prefix = '%s[%d].' % (name, i)
sub_errors = element.FindInitializationErrors()
errors += [prefix + error for error in sub_errors]
else:
- prefix = name + "."
+ prefix = name + '.'
sub_errors = value.FindInitializationErrors()
errors += [prefix + error for error in sub_errors]
@@ -1315,7 +1316,7 @@
def MergeFrom(self, msg):
if not isinstance(msg, cls):
raise TypeError(
- "Parameter to MergeFrom() must be instance of same class: "
+ 'Parameter to MergeFrom() must be instance of same class: '
'expected %s got %s.' % (cls.__name__, msg.__class__.__name__))
assert msg is not self
@@ -1611,8 +1612,8 @@
other_fields = other._extended_message.ListFields()
# Get rid of non-extension fields.
- my_fields = [ field for field in my_fields if field.is_extension ]
- other_fields = [ field for field in other_fields if field.is_extension ]
+ my_fields = [field for field in my_fields if field.is_extension]
+ other_fields = [field for field in other_fields if field.is_extension]
return my_fields == other_fields
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index ccf8ac1..3580677 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -50,9 +50,11 @@
from google.protobuf import any_pb2
from google.protobuf import any_test_pb2
from google.protobuf import map_unittest_pb2
+from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf import descriptor_pb2
from google.protobuf.internal import any_test_pb2 as test_extend_any
from google.protobuf.internal import message_set_extensions_pb2
from google.protobuf.internal import test_util
@@ -175,7 +177,10 @@
'repeated_nested_message {\n bb: 32\n}\n'
'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n')
if as_one_line:
- expected_ascii = expected_ascii.replace('\n ', '').replace('\n', '')
+ expected_ascii = expected_ascii.replace('\n', ' ')
+ expected_ascii = re.sub(r'\s+', ' ', expected_ascii)
+ expected_ascii = re.sub(r'\s$', '', expected_ascii)
+
actual_ascii = text_format.MessageToString(
message, use_short_repeated_primitives=True,
as_one_line=as_one_line)
@@ -184,7 +189,7 @@
text_format.Parse(actual_ascii, parsed_message)
self.assertEqual(parsed_message, message)
- def tesPrintShortFormatRepeatedFields(self, message_module, as_one_line):
+ def testPrintShortFormatRepeatedFields(self, message_module):
self.VerifyPrintShortFormatRepeatedFields(message_module, False)
self.VerifyPrintShortFormatRepeatedFields(message_module, True)
@@ -358,6 +363,63 @@
self.assertEqual('0.0', out.getvalue())
out.close()
+ def testCustomOptions(self, message_module):
+ message_descriptor = (unittest_custom_options_pb2.
+ TestMessageWithCustomOptions.DESCRIPTOR)
+ message_proto = descriptor_pb2.DescriptorProto()
+ message_descriptor.CopyToProto(message_proto)
+ expected_text = (
+ 'name: "TestMessageWithCustomOptions"\n'
+ 'field {\n'
+ ' name: "field1"\n'
+ ' number: 1\n'
+ ' label: LABEL_OPTIONAL\n'
+ ' type: TYPE_STRING\n'
+ ' options {\n'
+ ' ctype: CORD\n'
+ ' [protobuf_unittest.field_opt1]: 8765432109\n'
+ ' }\n'
+ '}\n'
+ 'field {\n'
+ ' name: "oneof_field"\n'
+ ' number: 2\n'
+ ' label: LABEL_OPTIONAL\n'
+ ' type: TYPE_INT32\n'
+ ' oneof_index: 0\n'
+ '}\n'
+ 'enum_type {\n'
+ ' name: "AnEnum"\n'
+ ' value {\n'
+ ' name: "ANENUM_VAL1"\n'
+ ' number: 1\n'
+ ' }\n'
+ ' value {\n'
+ ' name: "ANENUM_VAL2"\n'
+ ' number: 2\n'
+ ' options {\n'
+ ' [protobuf_unittest.enum_value_opt1]: 123\n'
+ ' }\n'
+ ' }\n'
+ ' options {\n'
+ ' [protobuf_unittest.enum_opt1]: -789\n'
+ ' }\n'
+ '}\n'
+ 'options {\n'
+ ' message_set_wire_format: false\n'
+ ' [protobuf_unittest.message_opt1]: -56\n'
+ '}\n'
+ 'oneof_decl {\n'
+ ' name: "AnOneof"\n'
+ ' options {\n'
+ ' [protobuf_unittest.oneof_opt1]: -99\n'
+ ' }\n'
+ '}\n')
+ self.assertEqual(expected_text,
+ text_format.MessageToString(message_proto))
+ parsed_proto = descriptor_pb2.DescriptorProto()
+ text_format.Parse(expected_text, parsed_proto)
+ self.assertEqual(message_proto, parsed_proto)
+
@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
class TextFormatMessageToTextBytesTests(TextFormatBase):
@@ -1907,6 +1969,30 @@
'repeated_nested_message { My lucky number is 42 } '
'repeated_nested_message { My lucky number is 99 }'))
+ out = text_format.TextWriter(False)
+ text_format.PrintField(
+ message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+ 'optional_nested_message'],
+ message.optional_nested_message,
+ out,
+ message_formatter=printer)
+ self.assertEqual(
+ 'optional_nested_message {\n My lucky number is 1\n}\n',
+ out.getvalue())
+ out.close()
+
+ out = text_format.TextWriter(False)
+ text_format.PrintFieldValue(
+ message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+ 'optional_nested_message'],
+ message.optional_nested_message,
+ out,
+ message_formatter=printer)
+ self.assertEqual(
+ '{\n My lucky number is 1\n}',
+ out.getvalue())
+ out.close()
+
class WhitespaceTest(TextFormatBase):
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
index 95c5615..92df148 100644
--- a/python/google/protobuf/internal/well_known_types.py
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -669,11 +669,7 @@
destination.ClearField(_StrConvert(name))
repeated_source = getattr(source, name)
repeated_destination = getattr(destination, name)
- if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
- for item in repeated_source:
- repeated_destination.add().MergeFrom(item)
- else:
- repeated_destination.extend(repeated_source)
+ repeated_destination.MergeFrom(repeated_source)
else:
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
if replace_message:
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
index 4dc2ae4..bf304b6 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -47,6 +47,7 @@
from google.protobuf import field_mask_pb2
from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2
+from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_pb2
from google.protobuf.internal import any_test_pb2
from google.protobuf.internal import test_util
@@ -526,7 +527,7 @@
out_mask.Intersect(mask1, mask2)
self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
- def testMergeMessage(self):
+ def testMergeMessageWithoutMapFields(self):
# Test merge one field.
src = unittest_pb2.TestAllTypes()
test_util.SetAllFields(src)
@@ -635,6 +636,29 @@
self.assertTrue(dst.HasField('foo_message'))
self.assertFalse(dst.HasField('foo_lazy_message'))
+ def testMergeMessageWithMapField(self):
+ empty_map = map_unittest_pb2.TestRecursiveMapMessage()
+ src_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+ src_level_2.a['src level 2'].CopyFrom(empty_map)
+ src = map_unittest_pb2.TestRecursiveMapMessage()
+ src.a['common key'].CopyFrom(src_level_2)
+ src.a['src level 1'].CopyFrom(src_level_2)
+
+ dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+ dst_level_2.a['dst level 2'].CopyFrom(empty_map)
+ dst = map_unittest_pb2.TestRecursiveMapMessage()
+ dst.a['common key'].CopyFrom(dst_level_2)
+ dst.a['dst level 1'].CopyFrom(empty_map)
+
+ mask = field_mask_pb2.FieldMask()
+ mask.FromJsonString('a')
+ mask.MergeMessage(src, dst)
+
+ # map from dst is replaced with map from src.
+ self.assertEqual(dst.a['common key'], src_level_2)
+ self.assertEqual(dst.a['src level 1'], src_level_2)
+ self.assertEqual(dst.a['dst level 1'], empty_map)
+
def testMergeErrors(self):
src = unittest_pb2.TestAllTypes()
dst = unittest_pb2.TestAllTypes()
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 3cb16b7..d5813d8 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -189,6 +189,21 @@
return descriptor->service()->file();
}
+bool Reparse(
+ PyMessageFactory* message_factory, const Message& from, Message* to) {
+ // Reparse message.
+ string serialized;
+ from.SerializeToString(&serialized);
+ io::CodedInputStream input(
+ reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
+ input.SetExtensionRegistry(message_factory->pool->pool,
+ message_factory->message_factory);
+ bool success = to->ParseFromCodedStream(&input);
+ if (!success) {
+ return false;
+ }
+ return true;
+}
// Converts options into a Python protobuf, and cache the result.
//
// This is a bit tricky because options can contain extension fields defined in
@@ -251,15 +266,8 @@
cmsg->message->CopyFrom(options);
} else {
// Reparse options string! XXX call cmessage::MergeFromString
- string serialized;
- options.SerializeToString(&serialized);
- io::CodedInputStream input(
- reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
- input.SetExtensionRegistry(message_factory->pool->pool,
- message_factory->message_factory);
- bool success = cmsg->message->MergePartialFromCodedStream(&input);
- if (!success) {
- PyErr_Format(PyExc_ValueError, "Error parsing Options message");
+ if (!Reparse(message_factory, options, cmsg->message)) {
+ PyErr_Format(PyExc_ValueError, "Error reparsing Options message");
return NULL;
}
}
@@ -290,6 +298,16 @@
DescriptorProtoClass* descriptor_message =
static_cast<DescriptorProtoClass*>(message->message);
descriptor->CopyTo(descriptor_message);
+ // Custom options might in unknown extensions. Reparse
+ // the descriptor_message. Can't skip reparse when options unknown
+ // fields is empty, because they might in sub descriptors' options.
+ PyMessageFactory* message_factory =
+ GetDefaultDescriptorPool()->py_message_factory;
+ if (!Reparse(message_factory, *descriptor_message, descriptor_message)) {
+ PyErr_Format(PyExc_ValueError, "Error reparsing descriptor message");
+ return nullptr;
+ }
+
Py_RETURN_NONE;
}
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 77c6170..9f74e2a 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -62,6 +62,7 @@
static Py_ssize_t Length(PyObject* _self);
static PyObject* GetIterator(PyObject *_self);
static PyObject* IterNext(PyObject* _self);
+ static PyObject* MergeFrom(PyObject* _self, PyObject* arg);
// Methods that differ between the map types.
static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
@@ -338,20 +339,19 @@
return reinterpret_cast<PyObject*>(message_class);
}
-PyObject* MergeFrom(PyObject* _self, PyObject* arg) {
+PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
MapContainer* self = GetMap(_self);
MapContainer* other_map = GetMap(arg);
Message* message = self->GetMutableMessage();
const Message* other_message = other_map->message;
const Reflection* reflection = message->GetReflection();
const Reflection* other_reflection = other_message->GetReflection();
- int count = other_reflection->FieldSize(
- *other_message, other_map->parent_field_descriptor);
- for (int i = 0 ; i < count; i ++) {
- reflection->AddMessage(message, self->parent_field_descriptor)->MergeFrom(
- other_reflection->GetRepeatedMessage(
- *other_message, other_map->parent_field_descriptor, i));
- }
+ internal::MapFieldBase* field = reflection->MapData(
+ message, self->parent_field_descriptor);
+ internal::MapFieldBase* other_field =
+ other_reflection->MapData(const_cast<Message*>(other_message),
+ self->parent_field_descriptor);
+ field->MergeFrom(*other_field);
self->version++;
Py_RETURN_NONE;
}
@@ -589,7 +589,7 @@
"Gets the value for the given key if present, or otherwise a default" },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." },
- { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
+ { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
"Merges a map into the current map." },
/*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
@@ -908,7 +908,7 @@
"Alias for getitem, useful to make explicit that the map is mutated." },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." },
- { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
+ { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
"Merges a map into the current map." },
/*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index fecb936..44df9fb 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -585,10 +585,6 @@
// Returns -1 on error and 0 on success.
template<class Visitor>
int ForEachCompositeField(CMessage* self, Visitor visitor) {
- Py_ssize_t pos = 0;
- PyObject* key;
- PyObject* field;
-
// Visit normal fields.
if (self->composite_fields) {
for (CMessage::CompositeFieldsMap::iterator it =
@@ -1554,10 +1550,11 @@
}
bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
+ auto message_name = field_descriptor->containing_type()->name();
if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
PyErr_Format(PyExc_ValueError,
- "Protocol message has no singular \"%s\" field.",
- field_descriptor->name().c_str());
+ "Protocol message %s has no singular \"%s\" field.",
+ message_name.c_str(), field_descriptor->name().c_str());
return false;
}
@@ -1565,8 +1562,8 @@
// HasField() for a oneof *itself* isn't supported.
if (in_oneof) {
PyErr_Format(PyExc_ValueError,
- "Can't test oneof field \"%s\" for presence in proto3, use "
- "WhichOneof instead.",
+ "Can't test oneof field \"%s.%s\" for presence in proto3, "
+ "use WhichOneof instead.", message_name.c_str(),
field_descriptor->containing_oneof()->name().c_str());
return false;
}
@@ -1579,8 +1576,8 @@
if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
PyErr_Format(
PyExc_ValueError,
- "Can't test non-submessage field \"%s\" for presence in proto3.",
- field_descriptor->name().c_str());
+ "Can't test non-submessage field \"%s.%s\" for presence in proto3.",
+ message_name.c_str(), field_descriptor->name().c_str());
return false;
}
}
@@ -1608,7 +1605,8 @@
FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
if (field_descriptor == NULL) {
if (!is_in_oneof) {
- PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
+ PyErr_Format(PyExc_ValueError, "Protocol message %s has no field %s.",
+ message->GetDescriptor()->name().c_str(), field_name);
return NULL;
} else {
Py_RETURN_FALSE;
@@ -2140,6 +2138,7 @@
reinterpret_cast<const uint8*>(data), data_length);
if (allow_oversize_protos) {
input.SetTotalBytesLimit(INT_MAX, INT_MAX);
+ input.SetRecursionLimit(INT_MAX);
}
PyMessageFactory* factory = GetFactoryForMessage(self);
input.SetExtensionRegistry(factory->pool->pool, factory->message_factory);
@@ -2822,8 +2821,6 @@
}
}
- const Descriptor* message_descriptor =
- (reinterpret_cast<CMessageClass*>(Py_TYPE(self)))->message_descriptor;
if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
PyErr_Format(PyExc_TypeError,
"descriptor to field '%s' doesn't apply to '%s' object",
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 998cd68..f7053c6 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -225,7 +225,8 @@
"""Print a single field name/value pair."""
printer = _Printer(out, indent, as_utf8, as_one_line,
use_short_repeated_primitives, pointy_brackets,
- use_index_order, float_format, message_formatter)
+ use_index_order, float_format,
+ message_formatter=message_formatter)
printer.PrintField(field, value)
@@ -243,7 +244,8 @@
"""Print a single field value (not including name)."""
printer = _Printer(out, indent, as_utf8, as_one_line,
use_short_repeated_primitives, pointy_brackets,
- use_index_order, float_format, message_formatter)
+ use_index_order, float_format,
+ message_formatter=message_formatter)
printer.PrintFieldValue(field, value)
@@ -427,8 +429,8 @@
def _PrintShortRepeatedPrimitivesValue(self, field, value):
# Note: this is called only when value has at least one element.
self._PrintFieldName(field)
- self.out.write('[')
- for i in xrange(len(value) - 1):
+ self.out.write(' [')
+ for i in six.moves.range(len(value) - 1):
self.PrintFieldValue(field, value[i])
self.out.write(', ')
self.PrintFieldValue(field, value[-1])
diff --git a/src/Makefile.am b/src/Makefile.am
index fc0df47..76250d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,7 +74,6 @@
google/protobuf/stubs/once.h \
google/protobuf/stubs/platform_macros.h \
google/protobuf/stubs/port.h \
- google/protobuf/stubs/singleton.h \
google/protobuf/stubs/status.h \
google/protobuf/stubs/stl_util.h \
google/protobuf/stubs/stringpiece.h \
@@ -92,6 +91,7 @@
google/protobuf/dynamic_message.h \
google/protobuf/empty.pb.h \
google/protobuf/extension_set.h \
+ google/protobuf/extension_set_inl.h \
google/protobuf/field_mask.pb.h \
google/protobuf/generated_enum_reflection.h \
google/protobuf/generated_enum_util.h \
@@ -112,6 +112,7 @@
google/protobuf/message_lite.h \
google/protobuf/metadata.h \
google/protobuf/metadata_lite.h \
+ google/protobuf/parse_context.h \
google/protobuf/port.h \
google/protobuf/port_def.inc \
google/protobuf/port_undef.inc \
@@ -314,7 +315,6 @@
google/protobuf/compiler/command_line_interface.cc \
google/protobuf/compiler/plugin.cc \
google/protobuf/compiler/plugin.pb.cc \
- google/protobuf/compiler/scc.cc \
google/protobuf/compiler/scc.h \
google/protobuf/compiler/subprocess.cc \
google/protobuf/compiler/subprocess.h \
@@ -528,7 +528,6 @@
EXTRA_DIST = \
$(protoc_inputs) \
- $(js_well_known_types_sources) \
solaris/libstdc++.la \
google/protobuf/test_messages_proto3.proto \
google/protobuf/test_messages_proto2.proto \
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index a45f658..156ac47 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -69,15 +69,17 @@
file_level_metadata_google_2fprotobuf_2fany_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fany_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] =
"\n\031google/protobuf/any.proto\022\017google.prot"
"obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
" \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
"%github.com/golang/protobuf/ptypes/any\242\002"
"\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
"roto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fany_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
"google/protobuf/any.proto", &assign_descriptors_table_google_2fprotobuf_2fany_2eproto, 205,
};
@@ -195,10 +197,10 @@
auto msg = static_cast<Any*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -208,14 +210,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Any.type_url");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_type_url();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_type_url();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// bytes value = 2;
@@ -223,25 +228,29 @@
if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- parser_till_end = ::google::protobuf::internal::StringParser;
- ::std::string* str = msg->mutable_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- str->append(ptr, size);
+ auto str = msg->mutable_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -252,7 +261,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index c931d50..57b7df8 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -134,7 +134,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Any& from);
void MergeFrom(const Any& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 1734dfd..7ecd8ef 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -144,8 +144,7 @@
file_level_metadata_google_2fprotobuf_2fapi_2eproto, 3, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fapi_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] =
"\n\031google/protobuf/api.proto\022\017google.prot"
"obuf\032$google/protobuf/source_context.pro"
"to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014"
@@ -165,7 +164,10 @@
"otobufB\010ApiProtoP\001Z+google.golang.org/ge"
"nproto/protobuf/api;api\242\002\003GPB\252\002\036Google.P"
"rotobuf.WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fapi_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
"google/protobuf/api.proto", &assign_descriptors_table_google_2fprotobuf_2fapi_2eproto, 750,
};
@@ -301,10 +303,10 @@
auto msg = static_cast<Api*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -314,14 +316,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Api.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.Method methods = 2;
@@ -366,14 +371,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Api.version");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_version();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_version();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// .google.protobuf.SourceContext source_context = 5;
@@ -422,13 +430,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -439,7 +447,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -971,10 +979,10 @@
auto msg = static_cast<Method*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -984,14 +992,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// string request_type_url = 2;
@@ -1000,14 +1011,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.request_type_url");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_request_type_url();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_request_type_url();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// bool request_streaming = 3;
@@ -1026,14 +1040,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.response_type_url");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_response_type_url();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_response_type_url();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// bool response_streaming = 5;
@@ -1077,13 +1094,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1094,7 +1111,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1596,10 +1613,10 @@
auto msg = static_cast<Mixin*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1609,14 +1626,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// string root = 2;
@@ -1625,26 +1645,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.root");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_root();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_root();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1655,7 +1678,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 40a609b..baa725f 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -128,7 +128,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Api& from);
void MergeFrom(const Api& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -318,7 +318,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Method& from);
void MergeFrom(const Method& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -501,7 +501,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Mixin& from);
void MergeFrom(const Mixin& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 26c291c..eb3a1dd 100644
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -33,6 +33,7 @@
#include <algorithm>
#include <limits>
+#include <google/protobuf/stubs/mutex.h>
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
@@ -323,24 +324,22 @@
}
void ArenaImpl::SerialArena::CleanupListFallback() {
- // Cleanup newest chunk: ptrs give us length.
+ // The first chunk might be only partially full, so calculate its size
+ // from cleanup_ptr_. Subsequent chunks are always full, so use list->size.
size_t n = cleanup_ptr_ - &cleanup_->nodes[0];
- CleanupNode* node = cleanup_ptr_;
- for (size_t i = 0; i < n; i++) {
- --node;
- node->cleanup(node->elem);
- }
-
- // Cleanup older chunks, which are known to be full.
- CleanupChunk* list = cleanup_->next;
- while (list) {
- size_t n = list->size;
- CleanupNode* node = &list->nodes[list->size];
- for (size_t i = 0; i < n; i++) {
- --node;
- node->cleanup(node->elem);
+ CleanupChunk* list = cleanup_;
+ while (true) {
+ CleanupNode* node = &list->nodes[0];
+ // Cleanup newest elements first (allocated last).
+ for (size_t i = n; i > 0; i--) {
+ node[i - 1].cleanup(node[i - 1].elem);
}
list = list->next;
+ if (list == nullptr) {
+ break;
+ }
+ // All but the first chunk are always full.
+ n = list->size;
}
}
diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h
index cab3d86..4ba5954 100644
--- a/src/google/protobuf/arena_impl.h
+++ b/src/google/protobuf/arena_impl.h
@@ -306,8 +306,10 @@
public:
// kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
// to protect the invariant that pos is always at a multiple of 8.
- static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & static_cast<size_t>(-8);
- static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
+ static const size_t kBlockHeaderSize =
+ (sizeof(Block) + 7) & static_cast<size_t>(-8);
+ static const size_t kSerialArenaSize =
+ (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 361b83e..a942cff 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -55,7 +55,7 @@
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format_lite.h>
#include <gtest/gtest.h>
-
+#include <google/protobuf/stubs/strutil.h>
using proto2_arena_unittest::ArenaMessage;
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 4d1ef09..5da9176 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -834,35 +834,51 @@
}
std::vector<const FileDescriptor*> parsed_files;
- // null unless descriptor_set_in_names_.empty()
std::unique_ptr<DiskSourceTree> disk_source_tree;
std::unique_ptr<ErrorPrinter> error_collector;
std::unique_ptr<DescriptorPool> descriptor_pool;
- std::unique_ptr<DescriptorDatabase> descriptor_database;
- if (descriptor_set_in_names_.empty()) {
- disk_source_tree.reset(new DiskSourceTree());
- if (!InitializeDiskSourceTree(disk_source_tree.get())) {
+ std::unique_ptr<SimpleDescriptorDatabase> descriptor_set_in_database;
+ std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database;
+
+ // Any --descriptor_set_in FileDescriptorSet objects will be used as a
+ // fallback to input_files on command line, so create that db first.
+ if (!descriptor_set_in_names_.empty()) {
+ descriptor_set_in_database.reset(new SimpleDescriptorDatabase());
+ if (!PopulateSimpleDescriptorDatabase(descriptor_set_in_database.get())) {
return 1;
}
+ }
+
+ if (proto_path_.empty()) {
+ // If there are no --proto_path flags, then just look in the specified
+ // --descriptor_set_in files. But first, verify that the input files are
+ // there.
+ if (!VerifyInputFilesInDescriptors(descriptor_set_in_database.get())) {
+ return 1;
+ }
+
+ error_collector.reset(new ErrorPrinter(error_format_));
+ descriptor_pool.reset(new DescriptorPool(descriptor_set_in_database.get(),
+ error_collector.get()));
+ } else {
+ disk_source_tree.reset(new DiskSourceTree());
+ if (!InitializeDiskSourceTree(disk_source_tree.get(),
+ descriptor_set_in_database.get())) {
+ return 1;
+ }
+
error_collector.reset(
new ErrorPrinter(error_format_, disk_source_tree.get()));
- SourceTreeDescriptorDatabase* database =
- new SourceTreeDescriptorDatabase(disk_source_tree.get());
- database->RecordErrorsTo(error_collector.get());
- descriptor_database.reset(database);
- descriptor_pool.reset(new DescriptorPool(
- descriptor_database.get(), database->GetValidationErrorCollector()));
- } else {
- error_collector.reset(new ErrorPrinter(error_format_));
+ source_tree_database.reset(new SourceTreeDescriptorDatabase(
+ disk_source_tree.get(), descriptor_set_in_database.get()));
+ source_tree_database->RecordErrorsTo(error_collector.get());
- SimpleDescriptorDatabase* database = new SimpleDescriptorDatabase();
- descriptor_database.reset(database);
- if (!PopulateSimpleDescriptorDatabase(database)) {
- return 1;
- }
- descriptor_pool.reset(new DescriptorPool(database, error_collector.get()));
+ descriptor_pool.reset(new DescriptorPool(
+ source_tree_database.get(),
+ source_tree_database->GetValidationErrorCollector()));
}
+
descriptor_pool->EnforceWeakDependencies(true);
if (!ParseInputFiles(descriptor_pool.get(), &parsed_files)) {
return 1;
@@ -980,7 +996,7 @@
}
bool CommandLineInterface::InitializeDiskSourceTree(
- DiskSourceTree* source_tree) {
+ DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
AddDefaultProtoPaths(&proto_path_);
// Set up the source tree.
@@ -989,7 +1005,7 @@
}
// Map input files to virtual paths if possible.
- if (!MakeInputsBeProtoPathRelative(source_tree)) {
+ if (!MakeInputsBeProtoPathRelative(source_tree, fallback_database)) {
return false;
}
@@ -1039,6 +1055,27 @@
return true;
}
+bool CommandLineInterface::VerifyInputFilesInDescriptors(
+ DescriptorDatabase* database) {
+ for (const auto& input_file : input_files_) {
+ FileDescriptorProto file_descriptor;
+ if (!database->FindFileByName(input_file, &file_descriptor)) {
+ std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
+ return false;
+ }
+
+ // Enforce --disallow_services.
+ if (disallow_services_ && file_descriptor.service_size() > 0) {
+ std::cerr << file_descriptor.name()
+ << ": This file contains services, but "
+ "--disallow_services was used."
+ << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
bool CommandLineInterface::ParseInputFiles(
DescriptorPool* descriptor_pool,
std::vector<const FileDescriptor*>* parsed_files) {
@@ -1051,9 +1088,6 @@
descriptor_pool->FindFileByName(input_file);
descriptor_pool->ClearUnusedImportTrackFiles();
if (parsed_file == NULL) {
- if (!descriptor_set_in_names_.empty()) {
- std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
- }
return false;
}
parsed_files->push_back(parsed_file);
@@ -1111,18 +1145,27 @@
}
bool CommandLineInterface::MakeProtoProtoPathRelative(
- DiskSourceTree* source_tree, string* proto) {
+ DiskSourceTree* source_tree, string* proto,
+ DescriptorDatabase* fallback_database) {
+ // If it's in the fallback db, don't report non-existent file errors.
+ FileDescriptorProto fallback_file;
+ bool in_fallback_database =
+ fallback_database != nullptr &&
+ fallback_database->FindFileByName(*proto, &fallback_file);
+
// If the input file path is not a physical file path, it must be a virtual
// path.
if (access(proto->c_str(), F_OK) < 0) {
string disk_file;
- if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) {
+ if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+ in_fallback_database) {
return true;
} else {
std::cerr << *proto << ": " << strerror(ENOENT) << std::endl;
return false;
}
}
+
string virtual_file, shadowing_disk_file;
switch (source_tree->DiskFileToVirtualFile(
*proto, &virtual_file, &shadowing_disk_file)) {
@@ -1138,13 +1181,17 @@
"comes first." << std::endl;
return false;
case DiskSourceTree::CANNOT_OPEN:
+ if (in_fallback_database) {
+ return true;
+ }
std::cerr << *proto << ": " << strerror(errno) << std::endl;
return false;
case DiskSourceTree::NO_MAPPING: {
// Try to interpret the path as a virtual path.
string disk_file;
- if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) {
- return true;
+ if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+ in_fallback_database) {
+ return true;
} else {
// The input file path can't be mapped to any --proto_path and it also
// can't be interpreted as a virtual path.
@@ -1166,9 +1213,10 @@
}
bool CommandLineInterface::MakeInputsBeProtoPathRelative(
- DiskSourceTree* source_tree) {
+ DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
for (auto& input_file : input_files_) {
- if (!MakeProtoProtoPathRelative(source_tree, &input_file)) {
+ if (!MakeProtoProtoPathRelative(source_tree, &input_file,
+ fallback_database)) {
return false;
}
}
@@ -1270,15 +1318,16 @@
return PARSE_ARGUMENT_FAIL;
}
- // If no --proto_path was given, use the current working directory.
- if (proto_path_.empty()) {
+ // The --proto_path & --descriptor_set_in flags both specify places to look
+ // for proto files. If neither were given, use the current working directory.
+ if (proto_path_.empty() && descriptor_set_in_names_.empty()) {
// Don't use make_pair as the old/default standard library on Solaris
// doesn't support it without explicit template parameters, which are
// incompatible with C++0x's make_pair.
proto_path_.push_back(std::pair<string, string>("", "."));
}
- // Check some errror cases.
+ // Check some error cases.
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
if (decoding_raw && !input_files_.empty()) {
std::cerr << "When using --decode_raw, no input files should be given."
@@ -1395,13 +1444,6 @@
input_files_.push_back(value);
} else if (name == "-I" || name == "--proto_path") {
- if (!descriptor_set_in_names_.empty()) {
- std::cerr << "Only one of " << name
- << " and --descriptor_set_in can be specified."
- << std::endl;
- return PARSE_ARGUMENT_FAIL;
- }
-
// Java's -classpath (and some other languages) delimits path components
// with colons. Let's accept that syntax too just to make things more
// intuitive.
@@ -1477,12 +1519,6 @@
std::cerr << name << " requires a non-empty value." << std::endl;
return PARSE_ARGUMENT_FAIL;
}
- if (!proto_path_.empty()) {
- std::cerr << "Only one of " << name
- << " and --proto_path can be specified."
- << std::endl;
- return PARSE_ARGUMENT_FAIL;
- }
if (!dependency_out_name_.empty()) {
std::cerr << name << " cannot be used with --dependency_out."
<< std::endl;
@@ -1698,13 +1734,18 @@
void CommandLineInterface::PrintHelpText() {
// Sorry for indentation here; line wrapping would be uglier.
- std::cout <<
-"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
+ std::cout
+ <<
+ "Usage: " << executable_name_
+ << " [OPTION] PROTO_FILES\n"
"Parse PROTO_FILES and generate output based on the options given:\n"
" -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
" imports. May be specified multiple times;\n"
" directories will be searched in order. If not\n"
" given, the current working directory is used.\n"
+" If not found in any of the these directories,\n"
+" the --descriptor_set_in descriptors will be\n"
+" checked for required proto file.\n"
" --version Show version info and exit.\n"
" -h, --help Show this text and exit.\n"
" --encode=MESSAGE_TYPE Read a text-format message of the given type\n"
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index cef29ff..48455e6 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -53,6 +53,7 @@
namespace protobuf {
class Descriptor; // descriptor.h
+class DescriptorDatabase; // descriptor_database.h
class DescriptorPool; // descriptor.h
class FileDescriptor; // descriptor.h
class FileDescriptorSet; // descriptor.h
@@ -214,14 +215,15 @@
// Clear state from previous Run().
void Clear();
- // Remaps the proto file so that it is relative to one of the ddirectories
+ // Remaps the proto file so that it is relative to one of the directories
// in proto_path_. Returns false if an error occurred.
- bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto);
+ bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto,
+ DescriptorDatabase* fallback_database);
// Remaps each file in input_files_ so that it is relative to one of the
// directories in proto_path_. Returns false if an error occurred.
- bool MakeInputsBeProtoPathRelative(
- DiskSourceTree* source_tree);
+ bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree,
+ DescriptorDatabase* fallback_database);
// Return status for ParseArguments() and InterpretArgument().
@@ -259,7 +261,11 @@
void PrintHelpText();
// Loads proto_path_ into the provided source_tree.
- bool InitializeDiskSourceTree(DiskSourceTree* source_tree);
+ bool InitializeDiskSourceTree(DiskSourceTree* source_tree,
+ DescriptorDatabase* fallback_database);
+
+ // Verify that all the input files exist in the given database.
+ bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database);
// Loads descriptor_set_in into the provided database
bool PopulateSimpleDescriptorDatabase(SimpleDescriptorDatabase* database);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 4e6f4af..4dc4725 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -299,7 +299,6 @@
void CommandLineInterfaceTest::RunWithArgs(std::vector<string> args) {
if (!disallow_plugins_) {
cli_.AllowPlugins("prefix-");
-#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
string plugin_path;
#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
@@ -330,11 +329,6 @@
#endif
if (plugin_path.empty()) {
-#else
- string plugin_path = "third_party/protobuf/test_plugin";
-
- if (access(plugin_path.c_str(), F_OK) != 0) {
-#endif // GOOGLE_THIRD_PARTY_PROTOBUF
GOOGLE_LOG(ERROR)
<< "Plugin executable not found. Plugin tests are likely to fail.";
} else {
@@ -1761,13 +1755,49 @@
TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
- ExpectErrorText(
- "Only one of --descriptor_set_in and --proto_path can be specified.\n");
+ ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
Run("protocol_compiler --test_out=$tmpdir "
"--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
- ExpectErrorText(
- "Only one of --proto_path and --descriptor_set_in can be specified.\n");
+ ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
+ // Test what happens if a proto is in a --descriptor_set_in and also exists
+ // on disk.
+ FileDescriptorSet file_descriptor_set;
+
+ // NOTE: This file desc SHOULD be different from the one created as a temp
+ // to make it easier to test that the file was output instead of the
+ // contents of the --descriptor_set_in file.
+ FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+ file_descriptor_proto->set_name("foo.proto");
+ file_descriptor_proto->add_message_type()->set_name("Foo");
+
+ WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message FooBar { required string foo_message = 1; }\n");
+
+ Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+ "--descriptor_set_in=$tmpdir/foo.bin "
+ "--include_source_info "
+ "--proto_path=$tmpdir foo.proto");
+
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+
+ EXPECT_EQ(1, descriptor_set.file_size());
+ EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+ // Descriptor set SHOULD have source code info.
+ EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+
+ EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
+ EXPECT_EQ("foo_message",
+ descriptor_set.file(0).message_type(0).field(0).name());
}
TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index a19ad59..0797fc2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -161,6 +161,10 @@
EXPECT_EQ("", error_collector.text_);
CppGenerator generator;
MockGeneratorContext context;
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+ generator.set_opensource_runtime(true);
+ generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
+#endif
string error;
ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 1e80715..214449a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -256,8 +256,6 @@
GenerateHeader(printer);
- IncludeFile("net/proto2/public/port_undef.inc", printer);
-
GenerateBottomHeaderGuard(printer, filename_identifier);
}
@@ -320,13 +318,11 @@
path = StringReplace(path, "internal/", "", false);
path = StringReplace(path, "proto/", "", false);
path = StringReplace(path, "public/", "", false);
- if (options_.opensource_include_paths) {
+ if (options_.runtime_include_base.empty()) {
format("#include <google/protobuf/$1$>", path);
} else {
- format(
- "#include "
- "\"third_party/protobuf/testing/extracted/src/google/protobuf/$1$\"",
- path);
+ format("#include \"$1$google/protobuf/$2$\"",
+ options_.runtime_include_base, path);
}
} else {
format("#include \"$1$\"", google3_name);
@@ -346,10 +342,10 @@
if (options_.opensource_runtime) {
if (IsWellKnownMessage(file)) {
- if (options_.opensource_include_paths) {
+ if (options_.runtime_include_base.empty()) {
use_system_include = true;
} else {
- name = "third_party/protobuf/testing/extracted/src/" + basename;
+ name = options_.runtime_include_base + basename;
}
}
}
@@ -809,36 +805,56 @@
"\n",
message_generators_.size());
- // Now generate the AddDescriptors() function.
- format(
- "::$proto_ns$::internal::DescriptorTable $1$ = {\n"
- " false, $init_defaults$, \n",
- UniqueName("descriptor_table", file_, options_));
- format.Indent();
-
// Embed the descriptor. We simply serialize the entire
- // FileDescriptorProto
- // and embed it as a string literal, which is parsed and built into real
- // descriptors at initialization time.
+ // FileDescriptorProto/ and embed it as a string literal, which is parsed and
+ // built into real descriptors at initialization time.
+ const string protodef_name =
+ UniqueName("descriptor_table_protodef", file_, options_);
+ format( "const char $1$[] =\n", protodef_name);
+ format.Indent();
FileDescriptorProto file_proto;
file_->CopyTo(&file_proto);
string file_data;
file_proto.SerializeToString(&file_data);
{
- // Only write 40 bytes per line.
- static const int kBytesPerLine = 40;
- for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
- format(
- "\"$1$\"\n",
- EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+ if (file_data.size() > 65535) {
+ // Workaround for MSVC: "Error C1091: compiler limit: string exceeds
+ // 65535 bytes in length". Declare a static array of chars rather than
+ // use a string literal. Only write 25 bytes per line.
+ static const int kBytesPerLine = 25;
+ format("{ ");
+ for (int i = 0; i < file_data.size();) {
+ for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+ format("'$1$', ", CEscape(file_data.substr(i, 1)));
+ }
+ format("\n");
+ }
+ format("'\\0' }"); // null-terminate
+ } else {
+ // Only write 40 bytes per line.
+ static const int kBytesPerLine = 40;
+ for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+ format(
+ "\"$1$\"\n",
+ EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+ }
}
+ format(";\n");
}
-
format.Outdent();
+
+ // Now generate the AddDescriptors() function.
+ format(
+ "::$proto_ns$::internal::DescriptorTable $1$ = {\n"
+ " false, $init_defaults$, \n"
+ " $2$,\n",
+ UniqueName("descriptor_table", file_, options_),
+ protodef_name);
+
const int num_deps = file_->dependency_count();
format(
- ",\n \"$filename$\", &$assign_desc_table$, $1$,\n"
+ " \"$filename$\", &$assign_desc_table$, $1$,\n"
"};\n\n"
"void $add_descriptors$() {\n"
" static constexpr ::$proto_ns$::internal::InitFunc deps[$2$] =\n"
@@ -1277,7 +1293,7 @@
IncludeFile("net/proto2/public/unknown_field_set.h", printer);
}
- if (IsAnyMessage(file_)) {
+ if (IsAnyMessage(file_, options_)) {
IncludeFile("net/proto2/internal/any.h", printer);
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 0e7e4df..e4fecd3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -78,19 +78,8 @@
//
Options file_options;
- switch (runtime_) {
- case Runtime::kGoogle3:
- file_options.opensource_runtime = false;
- break;
- case Runtime::kOpensource:
- file_options.opensource_runtime = true;
- file_options.opensource_include_paths = true;
- break;
- case Runtime::kOpensourceGoogle3:
- file_options.opensource_runtime = true;
- file_options.opensource_include_paths = false;
- break;
- }
+ file_options.opensource_runtime = opensource_runtime_;
+ file_options.runtime_include_base = runtime_include_base_;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "dllexport_decl") {
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
index 30363e7..469af9c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -66,8 +66,17 @@
kOpensourceGoogle3
};
- void set_runtime(Runtime runtime) {
- runtime_ = runtime;
+ void set_opensource_runtime(bool opensource) {
+ opensource_runtime_ = opensource;
+ }
+
+ // If set to a non-empty string, generated code will do:
+ // #include "<BASE>/google/protobuf/message.h"
+ // instead of:
+ // #include <google/protobuf/message.h>
+ // This has no effect if opensource_runtime = false.
+ void set_runtime_include_base(const std::string& base) {
+ runtime_include_base_ = base;
}
// implements CodeGenerator ----------------------------------------
@@ -77,7 +86,8 @@
std::string* error) const;
private:
- Runtime runtime_ = Runtime::kOpensource;
+ bool opensource_runtime_ = true;
+ std::string runtime_include_base_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 472c55f..a1cceec 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -789,13 +789,17 @@
}
}
-bool IsAnyMessage(const FileDescriptor* descriptor) {
- return descriptor->name() == kAnyProtoFile;
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
+ // For now we do not support Any in lite mode, so if we're building for lite
+ // then we just treat Any as if it's an ordinary message with no special
+ // behavior.
+ return descriptor->name() == kAnyProtoFile &&
+ GetOptimizeFor(descriptor, options) != FileOptions::LITE_RUNTIME;
}
-bool IsAnyMessage(const Descriptor* descriptor) {
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
return descriptor->name() == kAnyMessageName &&
- descriptor->file()->name() == kAnyProtoFile;
+ IsAnyMessage(descriptor->file(), options);
}
bool IsWellKnownMessage(const FileDescriptor* descriptor) {
@@ -1170,6 +1174,52 @@
wiretype != internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
}
+void GenerateStrings(const FieldDescriptor* field, const Options& options,
+ const Formatter& format, bool check_utf8) {
+ string utf8;
+ if (check_utf8) {
+ utf8 = GetUtf8Suffix(field, options);
+ if (!utf8.empty()) {
+ string name = "nullptr";
+ if (HasDescriptorMethods(field->file(), options)) {
+ name = "\"" + field->full_name() + "\"";
+ }
+ format("ctx->extra_parse_data().SetFieldName($1$);\n", name);
+ }
+ }
+ format(
+ "auto str = msg->$1$_$2$();\n"
+ "if (size > end - ptr + "
+ "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n"
+ " object = str;\n",
+ field->is_repeated() && !field->is_packable() ? "add" : "mutable",
+ FieldName(field));
+ string name;
+ if (field->options().ctype() == FieldOptions::STRING ||
+ (IsProto1(field->file(), options) &&
+ field->options().ctype() == FieldOptions::STRING_PIECE)) {
+ name = "GreedyStringParser";
+ format(" str->clear();\n");
+ // TODO(gerbens) evaluate security
+ format(" str->reserve(size);\n");
+ } else if (field->options().ctype() == FieldOptions::CORD) {
+ name = "CordParser";
+ format(" str->Clear();\n");
+ } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
+ name = "StringPieceParser";
+ format(" str->Clear();\n");
+ }
+ format(
+ " parser_till_end = ::$proto_ns$::internal::$1$$2$;\n"
+ " goto len_delim_till_end;\n"
+ "}\n"
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$("
+ "ptr, size, ctx));\n"
+ "::$proto_ns$::internal::Inline$1$(str, ptr, size, ctx);\n"
+ "ptr += size;\n",
+ name, utf8);
+}
+
void GenerateLengthDelim(
const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer,
@@ -1212,72 +1262,13 @@
field_type = FieldDescriptor::TYPE_BYTES;
}
}
- string utf8 = "";
switch (field_type) {
case FieldDescriptor::TYPE_STRING:
- utf8 = GetUtf8Suffix(field, options);
- if (!utf8.empty()) {
- string name = "nullptr";
- if (HasDescriptorMethods(field->file(), options)) {
- name = "\"" + field->full_name() + "\"";
- }
- format("ctx->extra_parse_data().SetFieldName($1$);\n", name);
- }
- PROTOBUF_FALLTHROUGH_INTENDED;
- case FieldDescriptor::TYPE_BYTES: {
- if (field->options().ctype() == FieldOptions::STRING ||
- (IsProto1(field->file(), options) &&
- field->options().ctype() == FieldOptions::STRING_PIECE)) {
- format(
- "parser_till_end = ::$proto_ns$::internal::StringParser$1$;\n"
- "$string$* str = msg->$2$_$3$();\n"
- "str->clear();\n",
- utf8,
- field->is_repeated() && !field->is_map() &&
- !field->is_packable()
- ? "add"
- : "mutable",
- FieldName(field));
- if (utf8.empty()) {
- // special case if there is no utf8 verification.
- format(
- "object = str;\n"
- "if (size > end - ptr) goto len_delim_till_end;\n"
- "str->append(ptr, size);\n"
- "ptr += size;\n");
- return;
- }
- } else if (field->options().ctype() == FieldOptions::CORD) {
- string cord_parser = "CordParser" + utf8;
- format(
- "parser_till_end = ::$proto_ns$::internal::$1$;\n"
- "auto* str = msg->$2$_$3$();\n"
- "str->Clear();\n",
- cord_parser,
- field->is_repeated() && !field->is_map() ? "add" : "mutable",
- FieldName(field));
- } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
- format(
- "parser_till_end = "
- "::$proto_ns$::internal::StringPieceParser$1$;\n"
- "::$proto_ns$::internal::StringPieceField* str = "
- "msg->$2$_$3$();\n"
- "str->Clear();\n",
- utf8,
- field->is_repeated() && !field->is_map() ? "add" : "mutable",
- FieldName(field));
- }
- format(
- "object = str;\n"
- "if (size > end - ptr) goto len_delim_till_end;\n"
- "auto newend = ptr + size;\n"
- "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n");
- if (!utf8.empty()) {
- // If utf8 verification is on this can fail.
- format("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
- }
+ GenerateStrings(field, options, format, true /* utf8 */);
break;
- }
+ case FieldDescriptor::TYPE_BYTES:
+ GenerateStrings(field, options, format, false /* utf8 */);
+ break;
case FieldDescriptor::TYPE_MESSAGE: {
GOOGLE_CHECK(field->message_type());
if (!IsProto1(field->file(), options) && field->is_map()) {
@@ -1306,6 +1297,36 @@
QualifiedClassName(field->message_type()), FieldName(field));
break;
}
+ if (!IsProto1(field->file(), options) && IsLazy(field, options)) {
+ if (field->containing_oneof() != nullptr) {
+ format(
+ "if (!msg->has_$1$()) {\n"
+ " msg->clear_$1$();\n"
+ " msg->$2$_.$1$_ = ::google::protobuf::Arena::CreateMessage<\n"
+ " ::google::protobuf::internal::LazyField>(msg->GetArenaNoVirtual());\n"
+ " msg->set_has_$1$();\n"
+ "}\n"
+ "auto parse_closure = msg->$2$_.$1$_->_ParseClosure();\n",
+ FieldName(field), field->containing_oneof()->name());
+ } else if (HasFieldPresence(field->file())) {
+ format(
+ "HasBitSetters::set_has_$1$(msg);\n"
+ "auto parse_closure = msg->$1$_._ParseClosure();\n",
+ FieldName(field));
+ } else {
+ format(
+ "auto parse_closure = msg->$1$_._ParseClosure();\n",
+ FieldName(field));
+ }
+ format(
+ "parser_till_end = parse_closure.func;\n"
+ "object = parse_closure.object;\n"
+ "if (size > end - ptr) goto len_delim_till_end;\n"
+ "auto newend = ptr + size;\n"
+ "GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(parse_closure, ptr, newend));\n"
+ "ptr = newend;\n");
+ break;
+ }
if (IsImplicitWeakField(field, options, scc_analyzer)) {
if (!field->is_repeated()) {
format("object = HasBitSetters::mutable_$1$(msg);\n",
@@ -1428,11 +1449,12 @@
format(
"parser_till_end = $1$::_InternalParse;\n"
"object = msg->$2$_$3$();\n"
- "bool ok = ctx->PrepareGroup(tag, &depth);\n"
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
- "ptr = parser_till_end(ptr, end, object, ctx);\n"
+ "auto res = ctx->ParseGroup(tag, {parser_till_end, object}, ptr, "
+ "end, "
+ "&depth);\n"
+ "ptr = res.first;\n"
"$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
- "if (ctx->GroupContinues(depth)) goto group_continues;\n",
+ "if (res.second) goto group_continues;\n",
QualifiedClassName(field->message_type()),
field->is_repeated() ? "add" : "mutable", FieldName(field));
break;
@@ -1542,11 +1564,11 @@
" auto msg = static_cast<$classname$*>(object);\n"
" $uint32$ size; (void)size;\n"
" int depth; (void)depth;\n"
+ " $uint32$ tag;\n"
" ::$proto_ns$::internal::ParseFunc parser_till_end; "
"(void)parser_till_end;\n"
" auto ptr = begin;\n"
" while (ptr < end) {\n"
- " $uint32$ tag;\n"
" ptr = Varint::Parse32Inline(ptr, &tag);\n"
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
" switch (tag >> 3) {\n");
@@ -1583,8 +1605,7 @@
"default: {\n"
"handle_unusual: (void)&&handle_unusual;\n"
" if ((tag & 7) == 4 || tag == 0) {\n"
- " bool ok = ctx->ValidEndGroup(tag);\n"
- " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
+ " ctx->EndGroup(tag);\n"
" return ptr;\n"
" }\n");
if (IsMapEntryMessage(descriptor)) {
@@ -1617,6 +1638,7 @@
" internal_default_instance(), &msg->_internal_metadata_, "
"ctx);\n"
" ptr = res.first;\n"
+ " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
" if (res.second) return ptr;\n"
" continue;\n"
"}\n");
@@ -1626,6 +1648,7 @@
" ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), "
"ctx);\n"
" ptr = res.first;\n"
+ " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
" if (res.second) return ptr;\n"
"}\n"); // default case
}
@@ -1643,8 +1666,8 @@
" $DCHK$(ptr >= end);\n"
// Group crossed end and must be continued. Either this a parse failure
// or we need to resume on the next chunk and thus save the state.
- " ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, "
- "depth);\n"
+ " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg},"
+ " {parser_till_end, object}, depth, tag));\n"
" return ptr;\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index b8431ae..bde2230 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -35,6 +35,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
+#include <algorithm>
#include <iterator>
#include <map>
#include <string>
@@ -411,8 +412,8 @@
"_";
}
-bool IsAnyMessage(const FileDescriptor* descriptor);
-bool IsAnyMessage(const Descriptor* descriptor);
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
bool IsWellKnownMessage(const FileDescriptor* descriptor);
@@ -471,7 +472,18 @@
}
private:
- SCCAnalyzer analyzer_;
+ struct DepsGenerator {
+ std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
+ std::vector<const Descriptor*> deps;
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (desc->field(i)->message_type()) {
+ deps.push_back(desc->field(i)->message_type());
+ }
+ }
+ return deps;
+ }
+ };
+ SCCAnalyzer<DepsGenerator> analyzer_;
Options options_;
std::map<const SCC*, MessageAnalysis> analysis_cache_;
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 4af5403..f9d87ed 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -1085,7 +1085,7 @@
format("void UnsafeArenaSwap($classname$* other);\n");
}
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
format(
"// implements Any -----------------------------------------------\n"
"\n"
@@ -1152,7 +1152,7 @@
format(
"void CopyFrom(const $classname$& from);\n"
"void MergeFrom(const $classname$& from);\n"
- "void Clear()$ clear_final$;\n"
+ "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear()$ clear_final$;\n"
"bool IsInitialized() const$ is_initialized_final$;\n"
"\n"
"size_t ByteSizeLong() const final;\n"
@@ -1430,7 +1430,7 @@
format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n");
}
// Generate _any_metadata_ for the Any type.
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n");
}
@@ -1931,7 +1931,7 @@
format.Outdent();
format("}\n");
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
format(
"void $classname$::PackFrom(const ::$proto_ns$::Message& message) {\n"
" _any_metadata_.PackFrom(message);\n"
@@ -2240,7 +2240,7 @@
default_val = field->default_value_string().empty()
? "&::" + variables_["proto_ns"] +
"::internal::fixed_address_empty_string"
- : "&" + Namespace(field) + " ::" + classname_ +
+ : "&" + QualifiedClassName(descriptor_) +
"::" + MakeDefaultName(field);
break;
case FieldOptions::CORD:
@@ -2548,7 +2548,7 @@
}
}
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)";
}
if (num_weak_fields_ > 0) {
@@ -2556,7 +2556,7 @@
}
string initializer_null = superclass + "(), _internal_metadata_(NULL)";
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
initializer_null += ", _any_metadata_(&type_url_, &value_)";
}
if (num_weak_fields_ > 0) {
@@ -2620,7 +2620,7 @@
format(",\n$1$_(from.$1$_)", FieldName(field));
}
- if (IsAnyMessage(descriptor_)) {
+ if (IsAnyMessage(descriptor_, options_)) {
format(",\n_any_metadata_(&type_url_, &value_)");
}
if (num_weak_fields_ > 0) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 84c1862..fc90bd7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -55,7 +55,7 @@
bool lite_implicit_weak_fields = false;
bool bootstrap = false;
bool opensource_runtime = false;
- bool opensource_include_paths = false;
+ std::string runtime_include_base;
int num_cc_files = 0;
std::string annotation_pragma_name;
std::string annotation_guard_name;
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index ecfabe6..af4f880 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -59,7 +59,7 @@
descriptor->default_value_string().empty()
? "&::" + (*variables)["proto_ns"] +
"::internal::GetEmptyStringAlreadyInited()"
- : "&" + Namespace(descriptor) + "::" + (*variables)["classname"] +
+ : "&" + QualifiedClassName(descriptor->containing_type()) +
"::" + default_variable_string + ".get()";
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
@@ -92,7 +92,7 @@
inlined_(false) {
// TODO(ckennelly): Handle inlining for any.proto.
- if (IsAnyMessage(descriptor_->containing_type())) {
+ if (IsAnyMessage(descriptor_->containing_type(), options_)) {
inlined_ = false;
}
if (descriptor_->containing_type()->options().map_entry()) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
index 898b1fb..0323e4e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.inc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
@@ -50,7 +50,7 @@
#include <vector>
#include <google/protobuf/unittest_no_arena.pb.h>
-
+#include <google/protobuf/stubs/strutil.h>
#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER)
// We exclude this large proto from cmake build because it's too large for
// visual studio to compile (report internal errors).
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 58498aa..9ea544d 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -120,10 +120,19 @@
SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
SourceTree* source_tree)
- : source_tree_(source_tree),
- error_collector_(NULL),
- using_validation_error_collector_(false),
- validation_error_collector_(this) {}
+ : source_tree_(source_tree),
+ fallback_database_(nullptr),
+ error_collector_(nullptr),
+ using_validation_error_collector_(false),
+ validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+ SourceTree* source_tree, DescriptorDatabase* fallback_database)
+ : source_tree_(source_tree),
+ fallback_database_(fallback_database),
+ error_collector_(nullptr),
+ using_validation_error_collector_(false),
+ validation_error_collector_(this) {}
SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
@@ -131,6 +140,10 @@
const string& filename, FileDescriptorProto* output) {
std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
if (input == NULL) {
+ if (fallback_database_ != nullptr &&
+ fallback_database_->FindFileByName(filename, output)) {
+ return true;
+ }
if (error_collector_ != NULL) {
error_collector_->AddError(filename, -1, 0,
source_tree_->GetLastErrorMessage());
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index cf6b012..cdd05ed 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -78,6 +78,11 @@
class PROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
public:
SourceTreeDescriptorDatabase(SourceTree* source_tree);
+
+ // If non-NULL, fallback_database will be checked if a file doesn't exist in
+ // the specified source_tree.
+ SourceTreeDescriptorDatabase(SourceTree* source_tree,
+ DescriptorDatabase* fallback_database);
~SourceTreeDescriptorDatabase();
// Instructs the SourceTreeDescriptorDatabase to report any parse errors
@@ -110,6 +115,7 @@
class SingleFileErrorCollector;
SourceTree* source_tree_;
+ DescriptorDatabase* fallback_database_;
MultiFileErrorCollector* error_collector_;
class PROTOBUF_EXPORT ValidationErrorCollector
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index c98c8b3..a170a91 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -56,14 +56,6 @@
namespace {
-bool EnableJavaPrimitiveExperiment() {
-#ifdef PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
- return PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT;
-#else // PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
- return false;
-#endif // !PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
-}
-
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
int messageBitIndex,
int builderBitIndex,
@@ -77,12 +69,11 @@
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
- if (EnableJavaPrimitiveExperiment() &&
- (javaType == JAVATYPE_BOOLEAN ||
- javaType == JAVATYPE_DOUBLE ||
- javaType == JAVATYPE_FLOAT ||
- javaType == JAVATYPE_INT ||
- javaType == JAVATYPE_LONG)) {
+ if (javaType == JAVATYPE_BOOLEAN ||
+ javaType == JAVATYPE_DOUBLE ||
+ javaType == JAVATYPE_FLOAT ||
+ javaType == JAVATYPE_INT ||
+ javaType == JAVATYPE_LONG) {
string capitalized_type = UnderscoresToCamelCase(
PrimitiveTypeName(javaType), /*cap_first_letter=*/true);
(*variables)["field_list_type"] =
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 5779d5e..7e547af 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -43,6 +43,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/scc.h>
#include <google/protobuf/compiler/js/well_known_types_embed.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -154,6 +155,12 @@
return StripSuffixString(filename, suffix);
}
+string GetSnakeFilename(const string& filename) {
+ string snake_name = filename;
+ ReplaceCharacters(&snake_name, "/", '_');
+ return snake_name;
+}
+
// Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
// file foo/bar/baz.js.
string GetJSFilename(const GeneratorOptions& options, const string& filename) {
@@ -199,9 +206,9 @@
return basename + "_pb";
}
-// Returns the fully normalized JavaScript path for the given
+// Returns the fully normalized JavaScript namespace for the given
// file descriptor's package.
-string GetFilePath(const GeneratorOptions& options,
+string GetNamespace(const GeneratorOptions& options,
const FileDescriptor* file) {
if (!options.namespace_prefix.empty()) {
return options.namespace_prefix;
@@ -234,7 +241,7 @@
string GetPrefix(const GeneratorOptions& options,
const FileDescriptor* file_descriptor,
const Descriptor* containing_type) {
- string prefix = GetFilePath(options, file_descriptor) +
+ string prefix = GetNamespace(options, file_descriptor) +
GetNestedMessageName(containing_type);
if (!prefix.empty()) {
prefix += ".";
@@ -246,9 +253,7 @@
// message descriptor.
string GetMessagePathPrefix(const GeneratorOptions& options,
const Descriptor* descriptor) {
- return GetPrefix(
- options, descriptor->file(),
- descriptor->containing_type());
+ return GetPrefix(options, descriptor->file(), descriptor->containing_type());
}
// Returns the fully normalized JavaScript path for the given
@@ -261,9 +266,9 @@
// Returns the fully normalized JavaScript path prefix for the given
// enumeration descriptor.
string GetEnumPathPrefix(const GeneratorOptions& options,
- const EnumDescriptor* enum_descriptor) {
+ const EnumDescriptor* enum_descriptor) {
return GetPrefix(options, enum_descriptor->file(),
- enum_descriptor->containing_type());
+ enum_descriptor->containing_type());
}
// Returns the fully normalized JavaScript path for the given
@@ -392,7 +397,7 @@
return result;
}
-string ToFileName(const string& input) {
+string ToLower(const string& input) {
string result;
result.reserve(input.size());
@@ -407,27 +412,77 @@
return result;
}
-// When we're generating one output file per type name, this is the filename
+// When we're generating one output file per SCC, this is the filename
// that top-level extensions should go in.
+// e.g. one proto file (test.proto):
+// package a;
+// extends Foo {
+// ...
+// }
+// If "with_filename" equals true, the extension filename will be
+// "proto.a_test_extensions.js", otherwise will be "proto.a.js"
string GetExtensionFileName(const GeneratorOptions& options,
- const FileDescriptor* file) {
- return options.output_dir + "/" + ToFileName(GetFilePath(options, file)) +
+ const FileDescriptor* file, bool with_filename) {
+ string snake_name = StripProto(GetSnakeFilename(file->name()));
+ return options.output_dir + "/" + ToLower(GetNamespace(options, file)) +
+ (with_filename ? ("_" + snake_name + "_extensions") : "") +
+ options.GetFileNameExtension();
+}
+// When we're generating one output file per SCC, this is the filename
+// that all messages in the SCC should go in.
+// If with_package equals true, filename will have package prefix,
+// If the filename length is longer than 200, the filename will be the
+// SCC's proto filename with suffix "_long_sccs_(index)" (if with_package equals
+// true it still has package prefix)
+string GetMessagesFileName(
+ const GeneratorOptions& options, const SCC* scc, bool with_package) {
+ static std::map<const Descriptor*, string>* long_name_dict =
+ new std::map<const Descriptor*, string>();
+ string package_base =
+ with_package
+ ? ToLower(
+ GetNamespace(options, scc->GetRepresentative()->file()) + "_")
+ : "";
+ string filename_base = "";
+ std::vector<string> all_message_names;
+ for (auto one_desc : scc->descriptors) {
+ if (one_desc->containing_type() == nullptr) {
+ all_message_names.push_back(ToLower(one_desc->name()));
+ }
+ }
+ sort(all_message_names.begin(), all_message_names.end());
+ for (auto one_message : all_message_names) {
+ if (!filename_base.empty()) {
+ filename_base += "_";
+ }
+ filename_base += one_message;
+ }
+ if (filename_base.size() + package_base.size() > 200) {
+ if ((*long_name_dict).find(scc->GetRepresentative()) ==
+ (*long_name_dict).end()) {
+ string snake_name = StripProto(
+ GetSnakeFilename(scc->GetRepresentative()->file()->name()));
+ (*long_name_dict)[scc->GetRepresentative()] =
+ StrCat(snake_name, "_long_sccs_",
+ static_cast<uint64>((*long_name_dict).size()));
+ }
+ filename_base = (*long_name_dict)[scc->GetRepresentative()];
+ }
+ return options.output_dir + "/" + package_base + filename_base +
options.GetFileNameExtension();
}
// When we're generating one output file per type name, this is the filename
-// that a top-level message should go in.
-string GetMessageFileName(const GeneratorOptions& options,
- const Descriptor* desc) {
- return options.output_dir + "/" + ToFileName(desc->name()) +
- options.GetFileNameExtension();
-}
-
-// When we're generating one output file per type name, this is the filename
-// that a top-level message should go in.
+// that a top-level enum should go in.
+// If with_package equals true, filename will have package prefix.
string GetEnumFileName(const GeneratorOptions& options,
- const EnumDescriptor* desc) {
- return options.output_dir + "/" + ToFileName(desc->name()) +
+ const EnumDescriptor* desc,
+ bool with_package) {
+ return options.output_dir + "/" +
+ (with_package
+ ? ToLower(GetNamespace(options, desc->file()) + "_")
+ : "") +
+ ToLower(desc->name()) +
options.GetFileNameExtension();
}
@@ -627,7 +682,7 @@
// JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
// Returns false if |out| was truncated because |in| contained invalid UTF-8 or
// codepoints outside the BMP.
-// TODO(lukestebbing): Support codepoints outside the BMP.
+// TODO(b/115551870): Support codepoints outside the BMP.
bool EscapeJSString(const string& in, string* out) {
size_t decoded = 0;
for (size_t i = 0; i < in.size(); i += decoded) {
@@ -659,7 +714,7 @@
case '\r': *out += "\\r"; break;
case '\\': *out += "\\\\"; break;
default:
- // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
+ // TODO(b/115551870): Once we're supporting codepoints outside the BMP,
// use a single Unicode codepoint escape if the output language is
// ECMAScript 2015 or above. Otherwise, use a surrogate pair.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
@@ -818,7 +873,7 @@
string out;
bool is_valid = EscapeJSString(field->default_value_string(), &out);
if (!is_valid) {
- // TODO(lukestebbing): Decide whether this should be a hard error.
+ // TODO(b/115551870): Decide whether this should be a hard error.
GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
<< " was truncated since it contained invalid UTF-8 or"
" codepoints outside the basic multilingual plane.";
@@ -1413,37 +1468,57 @@
}
// We use this to implement the semantics that same file can be generated
-// multiple times, but the last one wins. We never actually write the files,
-// but we keep a set of which descriptors were the final one for a given
-// filename.
+// multiple times, but only the last one keep the short name. Others all use
+// long name with extra information to distinguish (For message and enum, the
+// extra information is package name, for file level extension, the extra
+// information is proto's filename).
+// We never actually write the files, but we keep a set of which descriptors
+// were the final one for a given filename.
class FileDeduplicator {
public:
explicit FileDeduplicator(const GeneratorOptions& options)
: error_on_conflict_(options.error_on_name_conflict) {}
- bool AddFile(const string& filename, const void* desc, string* error) {
- if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
+ // params:
+ // filenames: a pair of {short filename, full filename}
+ // (short filename don't have extra information, full filename
+ // contains extra information)
+ // desc: The Descriptor or SCC pointer or EnumDescriptor.
+ // error: The returned error information.
+ bool AddFile(
+ const std::pair<string, string> filenames,
+ const void* desc, string* error) {
+ if (descs_by_shortname_.find(filenames.first) !=
+ descs_by_shortname_.end()) {
if (error_on_conflict_) {
- *error = "Name conflict: file name " + filename +
+ *error = "Name conflict: file name " + filenames.first +
" would be generated by two descriptors";
return false;
}
- allowed_descs_.erase(descs_by_filename_[filename]);
+ // Change old pointer's actual name to full name.
+ auto short_name_desc = descs_by_shortname_[filenames.first];
+ allowed_descs_actual_name_[short_name_desc] =
+ allowed_descs_full_name_[short_name_desc];
}
+ descs_by_shortname_[filenames.first] = desc;
+ allowed_descs_actual_name_[desc] = filenames.first;
+ allowed_descs_full_name_[desc] = filenames.second;
- descs_by_filename_[filename] = desc;
- allowed_descs_.insert(desc);
return true;
}
- void GetAllowedSet(std::set<const void*>* allowed_set) {
- *allowed_set = allowed_descs_;
+ void GetAllowedMap(std::map<const void*, string>* allowed_set) {
+ *allowed_set = allowed_descs_actual_name_;
}
private:
bool error_on_conflict_;
- std::map<string, const void*> descs_by_filename_;
- std::set<const void*> allowed_descs_;
+ // The map that restores all the descs that are using short name as filename.
+ std::map<string, const void*> descs_by_shortname_;
+ // The final actual filename map.
+ std::map<const void*, string> allowed_descs_actual_name_;
+ // The full name map.
+ std::map<const void*, string> allowed_descs_full_name_;
};
void DepthFirstSearch(const FileDescriptor* file,
@@ -1504,25 +1579,61 @@
// by choosing the last descriptor that writes each filename and permitting
// only those to generate code.
-bool GenerateJspbAllowedSet(const GeneratorOptions& options,
+struct DepsGenerator {
+ std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
+ std::vector<const Descriptor*> deps;
+ auto maybe_add = [&](const Descriptor* d) {
+ if (d) deps.push_back(d);
+ };
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (!IgnoreField(desc->field(i))) {
+ maybe_add(desc->field(i)->message_type());
+ }
+ }
+ for (int i = 0; i < desc->extension_count(); i++) {
+ maybe_add(desc->extension(i)->message_type());
+ maybe_add(desc->extension(i)->containing_type());
+ }
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ maybe_add(desc->nested_type(i));
+ }
+ maybe_add(desc->containing_type());
+
+ return deps;
+ }
+};
+
+bool GenerateJspbAllowedMap(const GeneratorOptions& options,
const std::vector<const FileDescriptor*>& files,
- std::set<const void*>* allowed_set,
+ std::map<const void*, string>* allowed_set,
+ SCCAnalyzer<DepsGenerator>* analyzer,
string* error) {
std::vector<const FileDescriptor*> files_ordered;
GenerateJspbFileOrder(files, &files_ordered);
// Choose the last descriptor for each filename.
FileDeduplicator dedup(options);
+ std::set<const SCC*> added;
for (int i = 0; i < files_ordered.size(); i++) {
for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
const Descriptor* desc = files_ordered[i]->message_type(j);
- if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
+ if (added.insert(analyzer->GetSCC(desc)).second && !dedup.AddFile(
+ std::make_pair(
+ GetMessagesFileName(options, analyzer->GetSCC(desc), false),
+ GetMessagesFileName(options, analyzer->GetSCC(desc), true)),
+ analyzer->GetSCC(desc),
+ error)) {
return false;
}
}
for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
- if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
+ if (!dedup.AddFile(
+ std::make_pair(
+ GetEnumFileName(options, desc, false),
+ GetEnumFileName(options, desc, true)),
+ desc,
+ error)) {
return false;
}
}
@@ -1537,14 +1648,17 @@
}
if (has_extension) {
- if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
- files_ordered[i], error)) {
+ if (!dedup.AddFile(
+ std::make_pair(
+ GetExtensionFileName(options, files_ordered[i], false),
+ GetExtensionFileName(options, files_ordered[i], true)),
+ files_ordered[i], error)) {
return false;
}
}
}
- dedup.GetAllowedSet(allowed_set);
+ dedup.GetAllowedMap(allowed_set);
return true;
}
@@ -1565,6 +1679,10 @@
printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64);
}
+bool IsWellKnownTypeFile(const FileDescriptor* file) {
+ return HasPrefixString(file->name(), "google/protobuf/");
+}
+
} // anonymous namespace
void Generator::GenerateHeader(const GeneratorOptions& options,
@@ -1647,7 +1765,7 @@
continue;
}
- string name = GetFilePath(options, field->file()) + "." +
+ string name = GetNamespace(options, field->file()) + "." +
JSObjectFieldName(options, field);
provided->insert(name);
}
@@ -1685,20 +1803,27 @@
}
}
-void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
- io::Printer* printer,
- const Descriptor* desc,
- std::set<string>* provided) const {
+void Generator::GenerateRequiresForSCC(const GeneratorOptions& options,
+ io::Printer* printer, const SCC* scc,
+ std::set<string>* provided) const {
std::set<string> required;
std::set<string> forwards;
bool have_message = false;
- FindRequiresForMessage(options, desc,
- &required, &forwards, &have_message);
+ bool has_extension = false;
+ bool has_map = false;
+ for (auto desc : scc->descriptors) {
+ if (desc->containing_type() == nullptr) {
+ FindRequiresForMessage(options, desc, &required, &forwards,
+ &have_message);
+ has_extension = (has_extension || HasExtensions(desc));
+ has_map = (has_map || HasMap(options, desc));
+ }
+ }
GenerateRequiresImpl(options, printer, &required, &forwards, provided,
- /* require_jspb = */ have_message,
- /* require_extension = */ HasExtensions(desc),
- /* require_map = */ HasMap(options, desc));
+ /* require_jspb = */ have_message,
+ /* require_extension = */ has_extension,
+ /* require_map = */ has_map);
}
void Generator::GenerateRequiresForLibrary(
@@ -1851,20 +1976,20 @@
const FieldDescriptor* field,
std::set<string>* required,
std::set<string>* forwards) const {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
- // N.B.: file-level extensions with enum type do *not* create
- // dependencies, as per original codegen.
- !(field->is_extension() && field->extension_scope() == NULL)) {
- if (options.add_require_for_enums) {
- required->insert(GetEnumPath(options, field->enum_type()));
- } else {
- forwards->insert(GetEnumPath(options, field->enum_type()));
- }
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- if (!IgnoreMessage(field->message_type())) {
- required->insert(GetMessagePath(options, field->message_type()));
- }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+ // N.B.: file-level extensions with enum type do *not* create
+ // dependencies, as per original codegen.
+ !(field->is_extension() && field->extension_scope() == nullptr)) {
+ if (options.add_require_for_enums) {
+ required->insert(GetEnumPath(options, field->enum_type()));
+ } else {
+ forwards->insert(GetEnumPath(options, field->enum_type()));
}
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (!IgnoreMessage(field->message_type())) {
+ required->insert(GetMessagePath(options, field->message_type()));
+ }
+ }
}
void Generator::FindRequiresForExtension(const GeneratorOptions& options,
@@ -1889,6 +2014,10 @@
io::Printer* printer,
const FileDescriptor* file) const {
for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateClassConstructorAndDeclareExtensionFieldInfo(
+ options, printer, file->message_type(i));
+ }
+ for (int i = 0; i < file->message_type_count(); i++) {
GenerateClass(options, printer, file->message_type(i));
}
for (int i = 0; i < file->enum_type_count(); i++) {
@@ -1905,7 +2034,6 @@
if (!NamespaceOnly(desc)) {
printer->Print("\n");
- GenerateClassConstructor(options, printer, desc);
GenerateClassFieldInfo(options, printer, desc);
@@ -1931,9 +2059,6 @@
if (!NamespaceOnly(desc)) {
GenerateClassRegistration(options, printer, desc);
GenerateClassFields(options, printer, desc);
- if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
- GenerateClassExtensionFieldInfo(options, printer, desc);
- }
if (options.import_style != GeneratorOptions::kImportClosure) {
for (int i = 0; i < desc->extension_count(); i++) {
@@ -1984,6 +2109,24 @@
"classname", GetMessagePath(options, desc));
}
+void Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ if (!NamespaceOnly(desc)) {
+ GenerateClassConstructor(options, printer, desc);
+ if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
+ GenerateClassExtensionFieldInfo(options, printer, desc);
+ }
+ }
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ if (!IgnoreMessage(desc->nested_type(i))) {
+ GenerateClassConstructorAndDeclareExtensionFieldInfo(
+ options, printer, desc->nested_type(i));
+ }
+ }
+}
+
void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
@@ -3222,7 +3365,7 @@
string extension_scope =
(field->extension_scope()
? GetMessagePath(options, field->extension_scope())
- : GetFilePath(options, field->file()));
+ : GetNamespace(options, field->file()));
const string extension_object_name = JSObjectFieldName(options, field);
printer->Print(
@@ -3397,8 +3540,8 @@
return kEverythingInOneFile;
}
- // Otherwise, we create one output file per type.
- return kOneOutputFilePerType;
+ // Otherwise, we create one output file per SCC.
+ return kOneOutputFilePerSCC;
}
void Generator::GenerateFilesInDepOrder(
@@ -3441,6 +3584,37 @@
}
}
+bool Generator::GenerateFile(const FileDescriptor* file,
+ const GeneratorOptions &options,
+ GeneratorContext* context,
+ bool use_short_name) const {
+ string filename =
+ options.output_dir + "/" + GetJSFilename(options,
+ use_short_name ? file->name().substr(file->name().rfind('/'))
+ : file->name());
+ std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+ GOOGLE_CHECK(output);
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ io::Printer printer(
+ output.get(), '$', options.annotate_code ?
+ &annotation_collector : nullptr);
+
+
+ GenerateFile(options, &printer, file);
+
+ if (printer.failed()) {
+ return false;
+ }
+
+ if (options.annotate_code) {
+ EmbedCodeAnnotations(annotations, &printer);
+ }
+
+ return true;
+}
+
void Generator::GenerateFile(const GeneratorOptions& options,
io::Printer* printer,
const FileDescriptor* file) const {
@@ -3479,7 +3653,7 @@
IgnoreField(file->extension(i))) {
continue;
}
- provided.insert(GetFilePath(options, file) + "." +
+ provided.insert(GetNamespace(options, file) + "." +
JSObjectFieldName(options, file->extension(i)));
extensions.insert(file->extension(i));
}
@@ -3505,10 +3679,10 @@
if (options.import_style == GeneratorOptions::kImportCommonJs &&
!provided.empty()) {
printer->Print("goog.object.extend(exports, $package$);\n",
- "package", GetFilePath(options, file));
+ "package", GetNamespace(options, file));
} else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
printer->Print("goog.object.extend(exports, proto);\n", "package",
- GetFilePath(options, file));
+ GetNamespace(options, file));
}
// Emit well-known type methods.
@@ -3570,21 +3744,36 @@
if (printer.failed()) {
return false;
}
- } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) {
- std::set<const void*> allowed_set;
- if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
+ } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerSCC) {
+ std::set<const Descriptor*> have_printed;
+ SCCAnalyzer<DepsGenerator> analyzer;
+ std::map<const void*, string> allowed_map;
+ if (!GenerateJspbAllowedMap(
+ options, files, &allowed_map, &analyzer, error)) {
return false;
}
+ bool generated = false;
for (int i = 0; i < files.size(); i++) {
const FileDescriptor* file = files[i];
+ // Force well known type to generate in a whole file.
+ if (IsWellKnownTypeFile(file)) {
+ if (!GenerateFile(file, options, context, true)) {
+ return false;
+ }
+ generated = true;
+ continue;
+ }
for (int j = 0; j < file->message_type_count(); j++) {
const Descriptor* desc = file->message_type(j);
- if (allowed_set.count(desc) == 0) {
+ if (have_printed.count(desc) ||
+ allowed_map.count(analyzer.GetSCC(desc)) == 0) {
continue;
}
- string filename = GetMessageFileName(options, desc);
+ generated = true;
+ const SCC* scc = analyzer.GetSCC(desc);
+ const string& filename = allowed_map[scc];
std::unique_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
GOOGLE_CHECK(output.get());
@@ -3593,12 +3782,30 @@
GenerateHeader(options, &printer);
std::set<string> provided;
- FindProvidesForMessage(options, &printer, desc, &provided);
+ for (auto one_desc : scc->descriptors) {
+ if (one_desc->containing_type() == nullptr) {
+ FindProvidesForMessage(options, &printer, one_desc, &provided);
+ }
+ }
GenerateProvides(options, &printer, &provided);
GenerateTestOnly(options, &printer);
- GenerateRequiresForMessage(options, &printer, desc, &provided);
+ GenerateRequiresForSCC(options, &printer, scc, &provided);
- GenerateClass(options, &printer, desc);
+ for (auto one_desc : scc->descriptors) {
+ if (one_desc->containing_type() == nullptr) {
+ GenerateClassConstructorAndDeclareExtensionFieldInfo(
+ options, &printer, one_desc);
+ }
+ }
+ for (auto one_desc : scc->descriptors) {
+ if (one_desc->containing_type() == nullptr) {
+ GenerateClass(options, &printer, one_desc);
+ }
+ }
+
+ for (auto one_desc : scc->descriptors) {
+ have_printed.insert(one_desc);
+ }
if (printer.failed()) {
return false;
@@ -3606,11 +3813,12 @@
}
for (int j = 0; j < file->enum_type_count(); j++) {
const EnumDescriptor* enumdesc = file->enum_type(j);
- if (allowed_set.count(enumdesc) == 0) {
+ if (allowed_map.count(enumdesc) == 0) {
continue;
}
- string filename = GetEnumFileName(options, enumdesc);
+ generated = true;
+ const string& filename = allowed_map[enumdesc];
std::unique_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
GOOGLE_CHECK(output.get());
@@ -3631,8 +3839,9 @@
}
// File-level extensions (message-level extensions are generated under
// the enclosing message).
- if (allowed_set.count(file) == 1) {
- string filename = GetExtensionFileName(options, file);
+ if (allowed_map.count(file) == 1) {
+ generated = true;
+ const string& filename = allowed_map[file];
std::unique_ptr<io::ZeroCopyOutputStream> output(
context->Open(filename));
@@ -3662,32 +3871,20 @@
}
}
}
+ if (!generated) {
+ string filename = options.output_dir + "/" +
+ "empty_no_content_void_file" + options.GetFileNameExtension();
+ std::unique_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filename));
+ }
} else /* options.output_mode() == kOneOutputFilePerInputFile */ {
// Generate one output file per input (.proto) file.
for (int i = 0; i < files.size(); i++) {
const FileDescriptor* file = files[i];
-
- string filename =
- options.output_dir + "/" + GetJSFilename(options, file->name());
- std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
- GOOGLE_CHECK(output.get());
- GeneratedCodeInfo annotations;
- io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
- &annotations);
- io::Printer printer(output.get(), '$',
- options.annotate_code ? &annotation_collector : NULL);
-
-
- GenerateFile(options, &printer, file);
-
- if (printer.failed()) {
+ if (!GenerateFile(file, options, context, false)) {
return false;
}
-
- if (options.annotate_code) {
- EmbedCodeAnnotations(annotations, &printer);
- }
}
}
return true;
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index 4567b07..a48750b 100644
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -38,6 +38,7 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/scc.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/port_def.inc>
@@ -98,7 +99,7 @@
// Create an output file for each input .proto file.
kOneOutputFilePerInputFile,
// Create an output file for each type.
- kOneOutputFilePerType,
+ kOneOutputFilePerSCC,
// Put everything in a single file named by the library option.
kEverythingInOneFile,
};
@@ -191,10 +192,10 @@
const GeneratorOptions& options, io::Printer* printer,
const std::vector<const FileDescriptor*>& files,
std::set<std::string>* provided) const;
- void GenerateRequiresForMessage(const GeneratorOptions& options,
- io::Printer* printer,
- const Descriptor* desc,
- std::set<std::string>* provided) const;
+ void GenerateRequiresForSCC(const GeneratorOptions& options,
+ io::Printer* printer,
+ const SCC* scc,
+ std::set<std::string>* provided) const;
// For extension fields at file scope.
void GenerateRequiresForExtensions(
const GeneratorOptions& options, io::Printer* printer,
@@ -218,7 +219,13 @@
const FieldDescriptor* field,
std::set<std::string>* required,
std::set<std::string>* forwards) const;
-
+ // Generate all things in a proto file into one file.
+ // If use_short_name is true, the generated file's name will only be short
+ // name that without directory, otherwise filename equals file->name()
+ bool GenerateFile(const FileDescriptor* file,
+ const GeneratorOptions &options,
+ GeneratorContext* context,
+ bool use_short_name) const;
void GenerateFile(const GeneratorOptions& options,
io::Printer* printer,
const FileDescriptor* file) const;
@@ -255,6 +262,10 @@
void GenerateClassFieldInfo(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const;
+ void GenerateClassConstructorAndDeclareExtensionFieldInfo(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
void GenerateClassXid(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const;
diff --git a/src/google/protobuf/compiler/js/well_known_types_embed.cc b/src/google/protobuf/compiler/js/well_known_types_embed.cc
index c00c60c..5cb7365 100644
--- a/src/google/protobuf/compiler/js/well_known_types_embed.cc
+++ b/src/google/protobuf/compiler/js/well_known_types_embed.cc
@@ -46,6 +46,7 @@
"\n"
"/**\n"
" * Packs the given message instance into this Any.\n"
+ " * For binary format usage only.\n"
" * @param {!Uint8Array} serialized The serialized data to pack.\n"
" * @param {string} name The type name of this message object.\n"
" * @param {string=} opt_typeUrlPrefix the type URL prefix.\n"
@@ -85,7 +86,8 @@
" } else {\n"
" return null;\n"
" }\n"
- "};\n"},
+ "};\n"
+ },
{"timestamp.js",
"/* This code will be inserted into generated code for\n"
" * google/protobuf/timestamp.proto. */\n"
@@ -109,6 +111,19 @@
"proto.google.protobuf.Timestamp.prototype.fromDate = function(value) {\n"
" this.setSeconds(Math.floor(value.getTime() / 1000));\n"
" this.setNanos(value.getMilliseconds() * 1000000);\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
+ " * Factory method that returns a Timestamp object with value equal to\n"
+ " * the given Date.\n"
+ " * @param {!Date} value The value to set.\n"
+ " * @return {!proto.google.protobuf.Timestamp}\n"
+ " */\n"
+ "proto.google.protobuf.Timestamp.fromDate = function(value) {\n"
+ " var timestamp = new proto.google.protobuf.Timestamp();\n"
+ " timestamp.fromDate(value);\n"
+ " return timestamp;\n"
"};\n"},
{"struct.js",
"/* This code will be inserted into generated code for\n"
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 8be2652..0b86049 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -55,10 +55,9 @@
cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
"Generate C++ header and source.");
-#ifdef GOOGLE_PROTOBUF_USE_OPENSOURCE_GOOGLE3_RUNTIME
- cpp_generator.set_runtime(cpp::CppGenerator::Runtime::kOpensourceGoogle3);
-#elif defined(GOOGLE_PROTOBUF_USE_OPENSOURCE_RUNTIME)
- cpp_generator.set_runtime(cpp::CppGenerator::Runtime::kOpensource);
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+ cpp_generator.set_opensource_runtime(true);
+ cpp_generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
#endif
// Proto2 Java
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 0cec293..c533c6a 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -2184,26 +2184,22 @@
file->clear_package();
}
+ LocationRecorder location(root_location,
+ FileDescriptorProto::kPackageFieldNumber);
+ location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
+
DO(Consume("package"));
- {
- LocationRecorder location(root_location,
- FileDescriptorProto::kPackageFieldNumber);
- location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
-
- while (true) {
- string identifier;
- DO(ConsumeIdentifier(&identifier, "Expected identifier."));
- file->mutable_package()->append(identifier);
- if (!TryConsume(".")) break;
- file->mutable_package()->append(".");
- }
-
- location.EndAt(input_->previous());
-
- DO(ConsumeEndOfDeclaration(";", &location));
+ while (true) {
+ string identifier;
+ DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+ file->mutable_package()->append(identifier);
+ if (!TryConsume(".")) break;
+ file->mutable_package()->append(".");
}
+ DO(ConsumeEndOfDeclaration(";", &location));
+
return true;
}
@@ -2212,31 +2208,30 @@
RepeatedField<int32>* weak_dependency,
const LocationRecorder& root_location,
const FileDescriptorProto* containing_file) {
+ LocationRecorder location(root_location,
+ FileDescriptorProto::kDependencyFieldNumber,
+ dependency->size());
+
DO(Consume("import"));
+
if (LookingAt("public")) {
- LocationRecorder location(
+ LocationRecorder public_location(
root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
public_dependency->size());
DO(Consume("public"));
*public_dependency->Add() = dependency->size();
} else if (LookingAt("weak")) {
- LocationRecorder location(
+ LocationRecorder weak_location(
root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
weak_dependency->size());
DO(Consume("weak"));
*weak_dependency->Add() = dependency->size();
}
- {
- LocationRecorder location(root_location,
- FileDescriptorProto::kDependencyFieldNumber,
- dependency->size());
- DO(ConsumeString(dependency->Add(),
- "Expected a string naming the file to import."));
- location.EndAt(input_->previous());
+ DO(ConsumeString(dependency->Add(),
+ "Expected a string naming the file to import."));
+ DO(ConsumeEndOfDeclaration(";", &location));
- DO(ConsumeEndOfDeclaration(";", &location));
- }
return true;
}
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 008d97d..e63739b 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -1693,7 +1693,7 @@
// Now try to define it as a package.
ExpectHasValidationErrors(
"package foo.bar;",
- "0:8: \"foo\" is already defined (as something other than a package) "
+ "0:0: \"foo\" is already defined (as something other than a package) "
"in file \"bar.proto\".\n");
}
@@ -2555,16 +2555,22 @@
TEST_F(SourceInfoTest, BasicFileDecls) {
EXPECT_TRUE(Parse(
"$a$syntax = \"proto2\";$i$\n"
- "package $b$foo.bar$c$;\n"
- "import $d$\"baz.proto\"$e$;\n"
- "import $f$\"qux.proto\"$g$;$h$\n"
+ "$b$package foo.bar;$c$\n"
+ "$d$import \"baz.proto\";$e$\n"
+ "$f$import\"qux.proto\";$h$\n"
+ "$j$import $k$public$l$ \"bar.proto\";$m$\n"
+ "$n$import $o$weak$p$ \"bar.proto\";$q$\n"
"\n"
"// comment ignored\n"));
- EXPECT_TRUE(HasSpan('a', 'h', file_));
+ EXPECT_TRUE(HasSpan('a', 'q', file_));
EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
- EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
+ EXPECT_TRUE(HasSpan('f', 'h', file_, "dependency", 1));
+ EXPECT_TRUE(HasSpan('j', 'm', file_, "dependency", 2));
+ EXPECT_TRUE(HasSpan('k', 'l', file_, "public_dependency", 0));
+ EXPECT_TRUE(HasSpan('n', 'q', file_, "dependency", 3));
+ EXPECT_TRUE(HasSpan('o', 'p', file_, "weak_dependency", 0));
EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
}
@@ -3301,7 +3307,7 @@
"// detached after empty before package\n"
"\n"
"// package leading\n"
- "package $c$foo$d$;\n"
+ "$c$package foo;$d$\n"
"// package trailing\n"
"\n"
"// ignored detach\n"
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 234be0d..171d1fe 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -179,8 +179,7 @@
file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto[] =
"\n%google/protobuf/compiler/plugin.proto\022"
"\030google.protobuf.compiler\032 google/protob"
"uf/descriptor.proto\"F\n\007Version\022\r\n\005major\030"
@@ -197,7 +196,10 @@
"content\030\017 \001(\tBg\n\034com.google.protobuf.com"
"pilerB\014PluginProtosZ9github.com/golang/p"
"rotobuf/protoc-gen-go/plugin;plugin_go"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
"google/protobuf/compiler/plugin.proto", &assign_descriptors_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 638,
};
@@ -314,10 +316,10 @@
auto msg = static_cast<Version*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -357,26 +359,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.Version.suffix");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_suffix();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_suffix();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -387,7 +392,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -795,10 +800,10 @@
auto msg = static_cast<CodeGeneratorRequest*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -809,14 +814,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->add_file_to_generate();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_file_to_generate();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
break;
@@ -827,14 +835,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.parameter");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_parameter();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_parameter();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional .google.protobuf.compiler.Version compiler_version = 3;
@@ -873,13 +884,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -890,7 +901,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1313,10 +1324,10 @@
auto msg = static_cast<CodeGeneratorResponse_File*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1326,14 +1337,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string insertion_point = 2;
@@ -1342,14 +1356,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_insertion_point();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_insertion_point();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string content = 15;
@@ -1358,26 +1375,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.content");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_content();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_content();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1388,7 +1408,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1761,10 +1781,10 @@
auto msg = static_cast<CodeGeneratorResponse*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1774,14 +1794,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.error");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_error();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_error();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
@@ -1805,13 +1828,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1822,7 +1845,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 187587c..6e8c8d2 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -147,7 +147,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Version& from);
void MergeFrom(const Version& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -299,7 +299,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const CodeGeneratorRequest& from);
void MergeFrom(const CodeGeneratorRequest& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -473,7 +473,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const CodeGeneratorResponse_File& from);
void MergeFrom(const CodeGeneratorResponse_File& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -633,7 +633,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const CodeGeneratorResponse& from);
void MergeFrom(const CodeGeneratorResponse& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 6dc61ec..ba7ecde 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -172,6 +172,7 @@
io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) {
// TODO(robinson): Allow parameterization of Python version?
printer->Print(
+ "# -*- coding: utf-8 -*-\n"
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"# source: $filename$\n"
"\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))" //##PY25
diff --git a/src/google/protobuf/compiler/scc.cc b/src/google/protobuf/compiler/scc.cc
deleted file mode 100644
index bbdabbf..0000000
--- a/src/google/protobuf/compiler/scc.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// 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.
-
-#include <google/protobuf/compiler/scc.h>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.h>
-
-namespace google {
-namespace protobuf {
-namespace compiler {
-
-SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
- // Must not have visited already.
- GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
-
- // Mark visited by inserting in map.
- NodeData& result = cache_[descriptor];
- // Initialize data structures.
- result.index = result.lowlink = index_++;
- stack_.push_back(descriptor);
-
- // Recurse the fields / nodes in graph
- for (int i = 0; i < descriptor->field_count(); i++) {
- const Descriptor* child = descriptor->field(i)->message_type();
- if (child) {
- if (cache_.count(child) == 0) {
- // unexplored node
- NodeData child_data = DFS(child);
- result.lowlink = std::min(result.lowlink, child_data.lowlink);
- } else {
- NodeData child_data = cache_[child];
- if (child_data.scc == nullptr) {
- // Still in the stack_ so we found a back edge
- result.lowlink = std::min(result.lowlink, child_data.index);
- }
- }
- }
- }
- if (result.index == result.lowlink) {
- // This is the root of a strongly connected component
- SCC* scc = CreateSCC();
- while (true) {
- const Descriptor* scc_desc = stack_.back();
- scc->descriptors.push_back(scc_desc);
- // Remove from stack
- stack_.pop_back();
- cache_[scc_desc].scc = scc;
-
- if (scc_desc == descriptor) break;
- }
-
- // The order of descriptors is random and depends how this SCC was
- // discovered. In-order to ensure maximum stability we sort it by name.
- std::sort(scc->descriptors.begin(), scc->descriptors.end(),
- [](const Descriptor* a, const Descriptor* b) {
- return a->full_name() < b->full_name();
- });
- AddChildren(scc);
- }
- return result;
-}
-
-void SCCAnalyzer::AddChildren(SCC* scc) {
- std::set<const SCC*> seen;
- for (int i = 0; i < scc->descriptors.size(); i++) {
- const Descriptor* descriptor = scc->descriptors[i];
- for (int j = 0; j < descriptor->field_count(); j++) {
- const Descriptor* child_msg = descriptor->field(j)->message_type();
- if (child_msg) {
- const SCC* child = GetSCC(child_msg);
- if (child == scc) continue;
- if (seen.insert(child).second) {
- scc->children.push_back(child);
- }
- }
- }
- }
-}
-
-} // namespace compiler
-} // namespace protobuf
-} // namespace google
diff --git a/src/google/protobuf/compiler/scc.h b/src/google/protobuf/compiler/scc.h
index c8cf77d..6243048 100644
--- a/src/google/protobuf/compiler/scc.h
+++ b/src/google/protobuf/compiler/scc.h
@@ -33,6 +33,8 @@
#include <map>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/port_def.inc>
@@ -54,6 +56,7 @@
// This class is used for analyzing the SCC for each message, to ensure linear
// instead of quadratic performance, if we do this per message we would get
// O(V*(V+E)).
+template <class DepsGenerator>
class PROTOC_EXPORT SCCAnalyzer {
public:
explicit SCCAnalyzer() : index_(0) {}
@@ -81,10 +84,69 @@
}
// Tarjan's Strongly Connected Components algo
- NodeData DFS(const Descriptor* descriptor);
+ NodeData DFS(const Descriptor* descriptor) {
+ // Must not have visited already.
+ GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
+
+ // Mark visited by inserting in map.
+ NodeData& result = cache_[descriptor];
+ // Initialize data structures.
+ result.index = result.lowlink = index_++;
+ stack_.push_back(descriptor);
+
+ // Recurse the fields / nodes in graph
+ for (auto dep : DepsGenerator()(descriptor)) {
+ GOOGLE_CHECK(dep);
+ if (cache_.count(dep) == 0) {
+ // unexplored node
+ NodeData child_data = DFS(dep);
+ result.lowlink = std::min(result.lowlink, child_data.lowlink);
+ } else {
+ NodeData child_data = cache_[dep];
+ if (child_data.scc == nullptr) {
+ // Still in the stack_ so we found a back edge
+ result.lowlink = std::min(result.lowlink, child_data.index);
+ }
+ }
+ }
+ if (result.index == result.lowlink) {
+ // This is the root of a strongly connected component
+ SCC* scc = CreateSCC();
+ while (true) {
+ const Descriptor* scc_desc = stack_.back();
+ scc->descriptors.push_back(scc_desc);
+ // Remove from stack
+ stack_.pop_back();
+ cache_[scc_desc].scc = scc;
+
+ if (scc_desc == descriptor) break;
+ }
+
+ // The order of descriptors is random and depends how this SCC was
+ // discovered. In-order to ensure maximum stability we sort it by name.
+ std::sort(scc->descriptors.begin(), scc->descriptors.end(),
+ [](const Descriptor* a, const Descriptor* b) {
+ return a->full_name() < b->full_name();
+ });
+ AddChildren(scc);
+ }
+ return result;
+ }
// Add the SCC's that are children of this SCC to its children.
- void AddChildren(SCC* scc);
+ void AddChildren(SCC* scc) {
+ std::set<const SCC*> seen;
+ for (auto descriptor : scc->descriptors) {
+ for (auto child_msg : DepsGenerator()(descriptor)) {
+ GOOGLE_CHECK(child_msg);
+ const SCC* child = GetSCC(child_msg);
+ if (child == scc) continue;
+ if (seen.insert(child).second) {
+ scc->children.push_back(child);
+ }
+ }
+ }
+ }
// This is necessary for compiler bug in msvc2015.
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SCCAnalyzer);
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 5bd3d43..66c6e2a 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -125,8 +125,10 @@
}
// Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'.
- // Using a malloc'ed string because CreateProcess() can mutate its second parameter. (WTF).
- char *command_line = portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
+ // Using a malloc'ed string because CreateProcess() can mutate its second
+ // parameter.
+ char *command_line =
+ portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
// Create the process.
PROCESS_INFORMATION process_info;
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 26f2b8c..5b7bd90 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -4498,6 +4498,7 @@
}
}
+
void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
const Descriptor* parent,
Descriptor* result) {
@@ -4546,6 +4547,7 @@
AddSymbol(result->full_name(), parent, result->name(),
proto, Symbol(result));
+
for (int i = 0; i < proto.reserved_range_size(); i++) {
const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i);
for (int j = i + 1; j < proto.reserved_range_size(); j++) {
@@ -4634,7 +4636,6 @@
}
}
-
void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
const Descriptor* parent,
FieldDescriptor* result,
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index f85ed13..a15884e 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1051,8 +1051,7 @@
file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, 27, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto, file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fdescriptor_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] =
"\n google/protobuf/descriptor.proto\022\017goog"
"le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
"\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
@@ -1204,7 +1203,10 @@
"Z>github.com/golang/protobuf/protoc-gen-"
"go/descriptor;descriptor\370\001\001\242\002\003GPB\252\002\032Goog"
"le.Protobuf.Reflection"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fdescriptor_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
"google/protobuf/descriptor.proto", &assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto, 6022,
};
@@ -1468,10 +1470,10 @@
auto msg = static_cast<FileDescriptorSet*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1496,13 +1498,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1513,7 +1515,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1929,10 +1931,10 @@
auto msg = static_cast<FileDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1942,14 +1944,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string package = 2;
@@ -1958,14 +1963,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.package");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_package();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_package();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated string dependency = 3;
@@ -1975,14 +1983,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.dependency");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->add_dependency();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_dependency();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
break;
@@ -2141,26 +2152,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.syntax");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_syntax();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_syntax();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2171,7 +2185,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2968,10 +2982,10 @@
auto msg = static_cast<DescriptorProto_ExtensionRange*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -3013,13 +3027,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -3030,7 +3044,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3393,10 +3407,10 @@
auto msg = static_cast<DescriptorProto_ReservedRange*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -3423,13 +3437,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -3440,7 +3454,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3831,10 +3845,10 @@
auto msg = static_cast<DescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -3844,14 +3858,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
@@ -4002,14 +4019,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.reserved_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->add_reserved_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_reserved_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 82 && (ptr += 1));
break;
@@ -4017,13 +4037,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -4034,7 +4054,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -4704,10 +4724,10 @@
auto msg = static_cast<ExtensionRangeOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -4732,20 +4752,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -4756,7 +4777,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -5189,10 +5210,10 @@
auto msg = static_cast<FieldDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -5202,14 +5223,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string extendee = 2;
@@ -5218,14 +5242,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.extendee");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_extendee();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_extendee();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional int32 number = 3;
@@ -5272,14 +5299,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.type_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_type_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_type_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string default_value = 7;
@@ -5288,14 +5318,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.default_value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_default_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_default_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional .google.protobuf.FieldOptions options = 8;
@@ -5329,26 +5362,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.json_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_json_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_json_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -5359,7 +5395,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6083,10 +6119,10 @@
auto msg = static_cast<OneofDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -6096,14 +6132,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.OneofDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional .google.protobuf.OneofOptions options = 2;
@@ -6124,13 +6163,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -6141,7 +6180,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6483,10 +6522,10 @@
auto msg = static_cast<EnumDescriptorProto_EnumReservedRange*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -6513,13 +6552,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -6530,7 +6569,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6901,10 +6940,10 @@
auto msg = static_cast<EnumDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -6914,14 +6953,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
@@ -6982,14 +7024,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.reserved_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->add_reserved_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_reserved_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
break;
@@ -6997,13 +7042,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -7014,7 +7059,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -7527,10 +7572,10 @@
auto msg = static_cast<EnumValueDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -7540,14 +7585,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValueDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional int32 number = 2;
@@ -7578,13 +7626,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -7595,7 +7643,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -8010,10 +8058,10 @@
auto msg = static_cast<ServiceDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -8023,14 +8071,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.ServiceDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
@@ -8069,13 +8120,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -8086,7 +8137,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -8548,10 +8599,10 @@
auto msg = static_cast<MethodDescriptorProto*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -8561,14 +8612,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string input_type = 2;
@@ -8577,14 +8631,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.input_type");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_input_type();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_input_type();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string output_type = 3;
@@ -8593,14 +8650,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.output_type");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_output_type();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_output_type();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional .google.protobuf.MethodOptions options = 4;
@@ -8641,13 +8701,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -8658,7 +8718,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -9353,10 +9413,10 @@
auto msg = static_cast<FileOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -9366,14 +9426,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_package");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_java_package();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_java_package();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string java_outer_classname = 8;
@@ -9382,14 +9445,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_outer_classname");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_java_outer_classname();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_java_outer_classname();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
@@ -9422,14 +9488,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.go_package");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_go_package();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_go_package();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional bool cc_generic_services = 16 [default = false];
@@ -9508,14 +9577,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.objc_class_prefix");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_objc_class_prefix();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_objc_class_prefix();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string csharp_namespace = 37;
@@ -9524,14 +9596,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.csharp_namespace");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_csharp_namespace();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_csharp_namespace();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string swift_prefix = 39;
@@ -9540,14 +9615,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.swift_prefix");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_swift_prefix();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_swift_prefix();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string php_class_prefix = 40;
@@ -9556,14 +9634,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_class_prefix");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_php_class_prefix();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_php_class_prefix();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string php_namespace = 41;
@@ -9572,14 +9653,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_namespace");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_php_namespace();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_php_namespace();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional bool php_generic_services = 42 [default = false];
@@ -9598,14 +9682,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_metadata_namespace");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_php_metadata_namespace();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_php_metadata_namespace();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string ruby_package = 45;
@@ -9614,14 +9701,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.ruby_package");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_ruby_package();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_ruby_package();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
@@ -9645,20 +9735,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -9669,7 +9760,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -10821,10 +10912,10 @@
auto msg = static_cast<MessageOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -10889,20 +10980,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -10913,7 +11005,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -11386,10 +11478,10 @@
auto msg = static_cast<FieldOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -11482,20 +11574,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -11506,7 +11599,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12025,10 +12118,10 @@
auto msg = static_cast<OneofOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -12053,20 +12146,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -12077,7 +12171,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12394,10 +12488,10 @@
auto msg = static_cast<EnumOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -12442,20 +12536,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -12466,7 +12561,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12846,10 +12941,10 @@
auto msg = static_cast<EnumValueOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -12884,20 +12979,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -12908,7 +13004,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -13250,10 +13346,10 @@
auto msg = static_cast<ServiceOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -13288,20 +13384,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -13312,7 +13409,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -13667,10 +13764,10 @@
auto msg = static_cast<MethodOptions*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -13719,20 +13816,21 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
if ((8000u <= tag)) {
auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
internal_default_instance(), &msg->_internal_metadata_, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
continue;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -13743,7 +13841,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -14140,10 +14238,10 @@
auto msg = static_cast<UninterpretedOption_NamePart*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -14153,14 +14251,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.NamePart.name_part");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_name_part();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name_part();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// required bool is_extension = 2;
@@ -14176,13 +14277,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -14193,7 +14294,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -14600,10 +14701,10 @@
auto msg = static_cast<UninterpretedOption*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -14631,14 +14732,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.identifier_value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_identifier_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_identifier_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional uint64 positive_int_value = 4;
@@ -14675,12 +14779,16 @@
if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- parser_till_end = ::google::protobuf::internal::StringParser;
- ::std::string* str = msg->mutable_string_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- str->append(ptr, size);
+ auto str = msg->mutable_string_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break;
}
@@ -14690,26 +14798,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.aggregate_value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_aggregate_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_aggregate_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -14720,7 +14831,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -15276,10 +15387,10 @@
auto msg = static_cast<SourceCodeInfo_Location*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -15335,14 +15446,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_comments");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_leading_comments();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_leading_comments();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional string trailing_comments = 4;
@@ -15351,14 +15465,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.trailing_comments");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_trailing_comments();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_trailing_comments();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated string leading_detached_comments = 6;
@@ -15368,14 +15485,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->add_leading_detached_comments();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_leading_detached_comments();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
break;
@@ -15383,13 +15503,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -15400,7 +15520,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -15898,10 +16018,10 @@
auto msg = static_cast<SourceCodeInfo*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -15926,13 +16046,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -15943,7 +16063,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -16252,10 +16372,10 @@
auto msg = static_cast<GeneratedCodeInfo_Annotation*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -16288,14 +16408,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.GeneratedCodeInfo.Annotation.source_file");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
- ::std::string* str = msg->mutable_source_file();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_source_file();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// optional int32 begin = 3;
@@ -16321,13 +16444,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -16338,7 +16461,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -16754,10 +16877,10 @@
auto msg = static_cast<GeneratedCodeInfo*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -16782,13 +16905,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -16799,7 +16922,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index c4b8365..b9245b2 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -372,7 +372,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FileDescriptorSet& from);
void MergeFrom(const FileDescriptorSet& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -512,7 +512,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FileDescriptorProto& from);
void MergeFrom(const FileDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -841,7 +841,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const DescriptorProto_ExtensionRange& from);
void MergeFrom(const DescriptorProto_ExtensionRange& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -997,7 +997,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const DescriptorProto_ReservedRange& from);
void MergeFrom(const DescriptorProto_ReservedRange& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1140,7 +1140,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const DescriptorProto& from);
void MergeFrom(const DescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1422,7 +1422,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const ExtensionRangeOptions& from);
void MergeFrom(const ExtensionRangeOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1565,7 +1565,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FieldDescriptorProto& from);
void MergeFrom(const FieldDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1948,7 +1948,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const OneofDescriptorProto& from);
void MergeFrom(const OneofDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -2113,7 +2113,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumDescriptorProto_EnumReservedRange& from);
void MergeFrom(const EnumDescriptorProto_EnumReservedRange& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -2256,7 +2256,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumDescriptorProto& from);
void MergeFrom(const EnumDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -2472,7 +2472,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumValueDescriptorProto& from);
void MergeFrom(const EnumValueDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -2645,7 +2645,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const ServiceDescriptorProto& from);
void MergeFrom(const ServiceDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -2823,7 +2823,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const MethodDescriptorProto& from);
void MergeFrom(const MethodDescriptorProto& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -3054,7 +3054,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FileOptions& from);
void MergeFrom(const FileOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -3555,7 +3555,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const MessageOptions& from);
void MergeFrom(const MessageOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -3730,7 +3730,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FieldOptions& from);
void MergeFrom(const FieldOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -3977,7 +3977,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const OneofOptions& from);
void MergeFrom(const OneofOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4120,7 +4120,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumOptions& from);
void MergeFrom(const EnumOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4279,7 +4279,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumValueOptions& from);
void MergeFrom(const EnumValueOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4430,7 +4430,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const ServiceOptions& from);
void MergeFrom(const ServiceOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4581,7 +4581,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const MethodOptions& from);
void MergeFrom(const MethodOptions& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4768,7 +4768,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const UninterpretedOption_NamePart& from);
void MergeFrom(const UninterpretedOption_NamePart& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -4931,7 +4931,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const UninterpretedOption& from);
void MergeFrom(const UninterpretedOption& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -5172,7 +5172,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const SourceCodeInfo_Location& from);
void MergeFrom(const SourceCodeInfo_Location& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -5400,7 +5400,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const SourceCodeInfo& from);
void MergeFrom(const SourceCodeInfo& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -5542,7 +5542,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const GeneratedCodeInfo_Annotation& from);
void MergeFrom(const GeneratedCodeInfo_Annotation& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -5724,7 +5724,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const GeneratedCodeInfo& from);
void MergeFrom(const GeneratedCodeInfo& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 02602d2..bc0cb3e 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -69,15 +69,17 @@
file_level_metadata_google_2fprotobuf_2fduration_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto, file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fduration_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto[] =
"\n\036google/protobuf/duration.proto\022\017google"
".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
"\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu"
"rationProtoP\001Z*github.com/golang/protobu"
"f/ptypes/duration\370\001\001\242\002\003GPB\252\002\036Google.Prot"
"obuf.WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fduration_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
"google/protobuf/duration.proto", &assign_descriptors_table_google_2fprotobuf_2fduration_2eproto, 227,
};
@@ -176,10 +178,10 @@
auto msg = static_cast<Duration*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -206,13 +208,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -223,7 +225,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 78d9466..25c55e8 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -125,7 +125,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Duration& from);
void MergeFrom(const Duration& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 9d0f9ae..724607c 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -67,14 +67,16 @@
file_level_metadata_google_2fprotobuf_2fempty_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto, file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fempty_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto[] =
"\n\033google/protobuf/empty.proto\022\017google.pr"
"otobuf\"\007\n\005EmptyBv\n\023com.google.protobufB\n"
"EmptyProtoP\001Z\'github.com/golang/protobuf"
"/ptypes/empty\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
".WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fempty_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
"google/protobuf/empty.proto", &assign_descriptors_table_google_2fprotobuf_2fempty_2eproto, 183,
};
@@ -162,23 +164,23 @@
auto msg = static_cast<Empty*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -189,7 +191,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 39b944b..4a40eca 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -125,7 +125,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Empty& from);
void MergeFrom(const Empty& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index ff2fc35..f63afef 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -38,6 +38,8 @@
#include <unordered_map>
#include <utility>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/message_lite.h>
@@ -48,9 +50,6 @@
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
namespace google {
namespace protobuf {
@@ -178,7 +177,11 @@
GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
type == WireFormatLite::TYPE_GROUP);
ExtensionInfo info(type, is_repeated, is_packed);
- info.message_prototype = prototype;
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+ info.message_info = {prototype, prototype->_ParseFunc()};
+#else
+ info.message_info = {prototype};
+#endif
Register(containing_type, number, info);
}
@@ -1215,194 +1218,8 @@
return UnknownFieldParse(tag, parent, begin, end,
metadata->mutable_unknown_fields(), ctx);
}
- auto ptr = begin;
- ParseClosure child;
- int depth;
- if (was_packed_on_wire) {
- switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \
- case WireFormatLite::TYPE_##UPPERCASE: \
- child = { \
- internal::Packed##CPP_CAMELCASE##Parser, \
- MutableRawRepeatedField(number, extension.type, extension.is_packed, \
- extension.descriptor)}; \
- goto length_delim
- HANDLE_TYPE(INT32, Int32);
- HANDLE_TYPE(INT64, Int64);
- HANDLE_TYPE(UINT32, UInt32);
- HANDLE_TYPE(UINT64, UInt64);
- HANDLE_TYPE(SINT32, SInt32);
- HANDLE_TYPE(SINT64, SInt64);
- HANDLE_TYPE(FIXED32, Fixed32);
- HANDLE_TYPE(FIXED64, Fixed64);
- HANDLE_TYPE(SFIXED32, SFixed32);
- HANDLE_TYPE(SFIXED64, SFixed64);
- HANDLE_TYPE(FLOAT, Float);
- HANDLE_TYPE(DOUBLE, Double);
- HANDLE_TYPE(BOOL, Bool);
-#undef HANDLE_TYPE
-
- case WireFormatLite::TYPE_ENUM:
- ctx->extra_parse_data().SetEnumValidatorArg(
- extension.enum_validity_check.func,
- extension.enum_validity_check.arg,
- metadata->mutable_unknown_fields(), tag >> 3);
- child = {
- internal::PackedValidEnumParserLiteArg,
- MutableRawRepeatedField(number, extension.type, extension.is_packed,
- extension.descriptor)};
- goto length_delim;
- case WireFormatLite::TYPE_STRING:
- case WireFormatLite::TYPE_BYTES:
- case WireFormatLite::TYPE_GROUP:
- case WireFormatLite::TYPE_MESSAGE:
- GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
- break;
- }
- } else {
- switch (extension.type) {
-#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- uint64 value; \
- ptr = Varint::Parse64(ptr, &value); \
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_VARINT_TYPE(INT32, Int32);
- HANDLE_VARINT_TYPE(INT64, Int64);
- HANDLE_VARINT_TYPE(UINT32, UInt32);
- HANDLE_VARINT_TYPE(UINT64, UInt64);
-#undef HANDLE_VARINT_TYPE
-#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- uint64 val; \
- ptr = Varint::Parse64(ptr, &val); \
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
- auto value = WireFormatLite::ZigZagDecode##SIZE(val); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
- HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
-#undef HANDLE_SVARINT_TYPE
-#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- CPPTYPE value; \
- std::memcpy(&value, ptr, sizeof(CPPTYPE)); \
- ptr += sizeof(CPPTYPE); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
- HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
- HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
- HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
- HANDLE_FIXED_TYPE(FLOAT, Float, float);
- HANDLE_FIXED_TYPE(DOUBLE, Double, double);
- HANDLE_FIXED_TYPE(BOOL, Bool, bool);
-#undef HANDLE_FIXED_TYPE
-
- case WireFormatLite::TYPE_ENUM: {
- uint64 val;
- ptr = Varint::Parse64(ptr, &val);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- int value = val;
-
- if (!extension.enum_validity_check.func(
- extension.enum_validity_check.arg, value)) {
- WriteVarint(number, val, metadata->mutable_unknown_fields());
- } else if (extension.is_repeated) {
- AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
- extension.descriptor);
- } else {
- SetEnum(number, WireFormatLite::TYPE_ENUM, value,
- extension.descriptor);
- }
- break;
- }
-
- case WireFormatLite::TYPE_BYTES:
- case WireFormatLite::TYPE_STRING: {
- string* value = extension.is_repeated
- ? AddString(number, WireFormatLite::TYPE_STRING,
- extension.descriptor)
- : MutableString(number, WireFormatLite::TYPE_STRING,
- extension.descriptor);
- child = {StringParser, value};
- goto length_delim;
- }
-
- case WireFormatLite::TYPE_GROUP: {
- MessageLite* value =
- extension.is_repeated
- ? AddMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype, extension.descriptor)
- : MutableMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype,
- extension.descriptor);
- child = {value->_ParseFunc(), value};
- bool ok = ctx->PrepareGroup(tag, &depth);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = child(ptr, end, ctx);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- if (ctx->GroupContinues(depth)) goto group_continues;
- break;
- }
-
- case WireFormatLite::TYPE_MESSAGE: {
- MessageLite* value =
- extension.is_repeated
- ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype, extension.descriptor)
- : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype,
- extension.descriptor);
- child = {value->_ParseFunc(), value};
- goto length_delim;
- }
- }
- }
-
- return std::make_pair(ptr, false);
-
-length_delim:
- uint32 size;
- ptr = Varint::Parse32Inline(ptr, &size);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- if (size > end - ptr) goto len_delim_till_end;
- {
- auto newend = ptr + size;
- bool ok = ctx->ParseExactRange(child, ptr, newend);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = newend;
- }
- return std::make_pair(ptr, false);
-len_delim_till_end:
- return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
- true);
-
-group_continues:
- ctx->StoreGroup(parent, child, depth);
- return std::make_pair(ptr, true);
+ return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
+ metadata, parent, begin, end, ctx);
}
#endif
@@ -1542,21 +1359,27 @@
}
case WireFormatLite::TYPE_GROUP: {
- MessageLite* value = extension.is_repeated ?
- AddMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype, extension.descriptor) :
- MutableMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype, extension.descriptor);
+ MessageLite* value =
+ extension.is_repeated
+ ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+ *extension.message_info.prototype,
+ extension.descriptor)
+ : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+ *extension.message_info.prototype,
+ extension.descriptor);
if (!WireFormatLite::ReadGroup(number, input, value)) return false;
break;
}
case WireFormatLite::TYPE_MESSAGE: {
- MessageLite* value = extension.is_repeated ?
- AddMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype, extension.descriptor) :
- MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype, extension.descriptor);
+ MessageLite* value =
+ extension.is_repeated
+ ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+ *extension.message_info.prototype,
+ extension.descriptor)
+ : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+ *extension.message_info.prototype,
+ extension.descriptor);
if (!WireFormatLite::ReadMessage(input, value)) return false;
break;
}
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index b31c8c4..57dbdef 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -47,16 +47,13 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/port.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
@@ -121,9 +118,16 @@
const void* arg;
};
+ struct MessageInfo {
+ const MessageLite* prototype;
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+ ParseFunc parse_func;
+#endif
+ };
+
union {
EnumValidityCheck enum_validity_check;
- const MessageLite* message_prototype;
+ MessageInfo message_info;
};
// The descriptor for this extension, if one exists and is known. May be
@@ -396,6 +400,11 @@
io::CodedOutputStream* unknown_fields);
#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+ template <typename T>
+ std::pair<const char*, bool> ParseFieldWithExtensionInfo(
+ int number, bool was_packed_on_wire, const ExtensionInfo& info,
+ T* metadata, ParseClosure parent, const char* begin, const char* end,
+ internal::ParseContext* ctx);
// Lite parser
std::pair<const char*, bool> ParseField(
uint64 tag, ParseClosure parent, const char* begin, const char* end,
@@ -408,6 +417,11 @@
const Message* containing_type,
internal::InternalMetadataWithArena* metadata,
internal::ParseContext* ctx);
+ std::pair<const char*, bool> ParseFieldMaybeLazily(
+ uint64 tag, ParseClosure parent, const char* begin, const char* end,
+ const Message* containing_type,
+ internal::InternalMetadataWithArena* metadata,
+ internal::ParseContext* ctx);
const char* ParseMessageSetItem(ParseClosure parent, const char* begin,
const char* end,
const Message* containing_type,
@@ -799,6 +813,7 @@
};
#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
template <typename Msg, typename Metadata>
const char* ParseMessageSet(const char* begin, const char* end, Msg* msg,
ExtensionSet* ext, Metadata* metadata,
@@ -811,26 +826,27 @@
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (tag == WireFormatLite::kMessageSetItemStartTag) {
- bool ok = ctx->PrepareGroup(tag, &depth);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
ctx->extra_parse_data().payload.clear();
- ptr = Msg::InternalParseMessageSetItem(ptr, end, msg, ctx);
+ auto res = ctx->ParseGroup(tag, {Msg::InternalParseMessageSetItem, msg},
+ ptr, end, &depth);
+ ptr = res.first;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- if (ctx->GroupContinues(depth)) goto group_continues;
+ if (res.second) {
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup(
+ {Msg::_InternalParse, msg}, {Msg::InternalParseMessageSetItem, msg},
+ depth, tag));
+ return ptr;
+ }
} else {
auto res =
ext->ParseField(tag, {Msg::_InternalParse, msg}, ptr, end,
Msg::internal_default_instance(), metadata, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (res.second) break;
}
}
return ptr;
-group_continues:
- GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({Msg::_InternalParse, msg},
- {Msg::InternalParseMessageSetItem, msg}, depth);
- return ptr;
}
#endif
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 20d36ab..90a96b5 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -35,12 +35,15 @@
// Contains methods defined in extension_set.h which cannot be part of the
// lite library because they use descriptors or reflection.
+#include <google/protobuf/extension_set.h>
+
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.h>
-#include <google/protobuf/extension_set.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/unknown_field_set.h>
@@ -301,11 +304,15 @@
output->is_packed = extension->options().packed();
output->descriptor = extension;
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- output->message_prototype =
+ output->message_info.prototype =
factory_->GetPrototype(extension->message_type());
- GOOGLE_CHECK(output->message_prototype != NULL)
+ GOOGLE_CHECK(output->message_info.prototype != nullptr)
<< "Extension factory's GetPrototype() returned NULL for extension: "
<< extension->full_name();
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+ output->message_info.parse_func =
+ output->message_info.prototype->_ParseFunc();
+#endif
} else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
output->enum_validity_check.func = ValidateEnumUsingDescriptor;
output->enum_validity_check.arg = extension->enum_type();
@@ -315,6 +322,7 @@
}
}
+
#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
bool ExtensionSet::FindExtension(int wire_type, uint32 field,
const Message* containing_type,
@@ -352,194 +360,16 @@
return UnknownFieldParse(tag, parent, begin, end,
metadata->mutable_unknown_fields(), ctx);
}
- auto ptr = begin;
- ParseClosure child;
- int depth;
- if (was_packed_on_wire) {
- switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \
- case WireFormatLite::TYPE_##UPPERCASE: \
- child = { \
- internal::Packed##CPP_CAMELCASE##Parser, \
- MutableRawRepeatedField(number, extension.type, extension.is_packed, \
- extension.descriptor)}; \
- goto length_delim
- HANDLE_TYPE(INT32, Int32);
- HANDLE_TYPE(INT64, Int64);
- HANDLE_TYPE(UINT32, UInt32);
- HANDLE_TYPE(UINT64, UInt64);
- HANDLE_TYPE(SINT32, SInt32);
- HANDLE_TYPE(SINT64, SInt64);
- HANDLE_TYPE(FIXED32, Fixed32);
- HANDLE_TYPE(FIXED64, Fixed64);
- HANDLE_TYPE(SFIXED32, SFixed32);
- HANDLE_TYPE(SFIXED64, SFixed64);
- HANDLE_TYPE(FLOAT, Float);
- HANDLE_TYPE(DOUBLE, Double);
- HANDLE_TYPE(BOOL, Bool);
-#undef HANDLE_TYPE
+ return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
+ metadata, parent, begin, end, ctx);
+}
- case WireFormatLite::TYPE_ENUM:
- ctx->extra_parse_data().SetEnumValidatorArg(
- extension.enum_validity_check.func,
- extension.enum_validity_check.arg,
- metadata->mutable_unknown_fields(), tag >> 3);
- child = {
- internal::PackedValidEnumParserArg,
- MutableRawRepeatedField(number, extension.type, extension.is_packed,
- extension.descriptor)};
- goto length_delim;
- case WireFormatLite::TYPE_STRING:
- case WireFormatLite::TYPE_BYTES:
- case WireFormatLite::TYPE_GROUP:
- case WireFormatLite::TYPE_MESSAGE:
- GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
- break;
- }
- } else {
- switch (extension.type) {
-#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- uint64 value; \
- ptr = Varint::Parse64(ptr, &value); \
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_VARINT_TYPE(INT32, Int32);
- HANDLE_VARINT_TYPE(INT64, Int64);
- HANDLE_VARINT_TYPE(UINT32, UInt32);
- HANDLE_VARINT_TYPE(UINT64, UInt64);
-#undef HANDLE_VARINT_TYPE
-#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- uint64 val; \
- ptr = Varint::Parse64(ptr, &val); \
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
- auto value = WireFormatLite::ZigZagDecode##SIZE(val); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
- HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
-#undef HANDLE_SVARINT_TYPE
-#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \
- case WireFormatLite::TYPE_##UPPERCASE: { \
- CPPTYPE value; \
- std::memcpy(&value, ptr, sizeof(CPPTYPE)); \
- ptr += sizeof(CPPTYPE); \
- if (extension.is_repeated) { \
- Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
- extension.is_packed, value, extension.descriptor); \
- } else { \
- Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
- extension.descriptor); \
- } \
- } break
-
- HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
- HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
- HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
- HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
- HANDLE_FIXED_TYPE(FLOAT, Float, float);
- HANDLE_FIXED_TYPE(DOUBLE, Double, double);
- HANDLE_FIXED_TYPE(BOOL, Bool, bool);
-#undef HANDLE_FIXED_TYPE
-
- case WireFormatLite::TYPE_ENUM: {
- uint64 val;
- ptr = Varint::Parse64(ptr, &val);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- int value = val;
-
- if (!extension.enum_validity_check.func(
- extension.enum_validity_check.arg, value)) {
- WriteVarint(number, val, metadata->mutable_unknown_fields());
- } else if (extension.is_repeated) {
- AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
- extension.descriptor);
- } else {
- SetEnum(number, WireFormatLite::TYPE_ENUM, value,
- extension.descriptor);
- }
- break;
- }
-
- case WireFormatLite::TYPE_BYTES:
- case WireFormatLite::TYPE_STRING: {
- string* value = extension.is_repeated
- ? AddString(number, WireFormatLite::TYPE_STRING,
- extension.descriptor)
- : MutableString(number, WireFormatLite::TYPE_STRING,
- extension.descriptor);
- child = {StringParser, value};
- goto length_delim;
- }
-
- case WireFormatLite::TYPE_GROUP: {
- MessageLite* value =
- extension.is_repeated
- ? AddMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype, extension.descriptor)
- : MutableMessage(number, WireFormatLite::TYPE_GROUP,
- *extension.message_prototype,
- extension.descriptor);
- child = {value->_ParseFunc(), value};
- bool ok = ctx->PrepareGroup(tag, &depth);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = child(ptr, end, ctx);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- if (ctx->GroupContinues(depth)) goto group_continues;
- break;
- }
-
- case WireFormatLite::TYPE_MESSAGE: {
- MessageLite* value =
- extension.is_repeated
- ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype, extension.descriptor)
- : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype,
- extension.descriptor);
- child = {value->_ParseFunc(), value};
- goto length_delim;
- }
- }
- }
-
- return std::make_pair(ptr, false);
-
-length_delim:
- uint32 size;
- ptr = Varint::Parse32Inline(ptr, &size);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- if (size > end - ptr) goto len_delim_till_end;
- {
- auto newend = ptr + size;
- bool ok = ctx->ParseExactRange(child, ptr, newend);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = newend;
- }
- return std::make_pair(ptr, false);
-len_delim_till_end:
- return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
- true);
-
-group_continues:
- ctx->StoreGroup(parent, child, depth);
- return std::make_pair(ptr, true);
+std::pair<const char*, bool> ExtensionSet::ParseFieldMaybeLazily(
+ uint64 tag, ParseClosure parent, const char* begin, const char* end,
+ const Message* containing_type,
+ internal::InternalMetadataWithArena* metadata,
+ internal::ParseContext* ctx) {
+ return ParseField(tag, parent, begin, end, containing_type, metadata, ctx);
}
#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -576,13 +406,14 @@
tag = *ptr++;
GOOGLE_PROTOBUF_PARSER_ASSERT(tag ==
WireFormatLite::kMessageSetMessageTag);
- auto res = ParseField(static_cast<uint64>(type_id) * 8 + 2, parent, ptr,
- end, containing_type, metadata, ctx);
+ auto res =
+ ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, parent,
+ ptr, end, containing_type, metadata, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) break;
} else {
ExtensionInfo extension;
- GeneratedExtensionFinder finder(containing_type);
bool was_packed_on_wire;
if (!FindExtension(2, type_id, containing_type, ctx, &extension,
&was_packed_on_wire)) {
@@ -593,18 +424,18 @@
MessageLite* value =
extension.is_repeated
? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype, extension.descriptor)
+ *extension.message_info.prototype,
+ extension.descriptor)
: MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
- *extension.message_prototype,
+ *extension.message_info.prototype,
extension.descriptor);
- ParseClosure parser = {value->_ParseFunc(), value};
- StringPiece chunk(ctx->extra_parse_data().payload.data());
+ ParseClosure parser = {extension.message_info.parse_func, value};
+ StringPiece chunk(ctx->extra_parse_data().payload);
bool ok = ctx->ParseExactRange(parser, chunk.begin(), chunk.end());
GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
}
} else if (tag == WireFormatLite::kMessageSetItemEndTag) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
break;
} else if (tag == WireFormatLite::kMessageSetMessageTag) {
uint32 size;
@@ -612,13 +443,12 @@
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ParseClosure child = {internal::StringParser,
&ctx->extra_parse_data().payload};
- if (size > end - ptr) {
+ if (size > end - ptr + internal::ParseContext::kSlopBytes) {
+ ctx->extra_parse_data().payload.clear();
return ctx->StoreAndTailCall(ptr, end, parent, child, size);
} else {
- auto newend = ptr + size;
- bool ok = ctx->ParseExactRange(child, ptr, newend);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
- ptr = newend;
+ ctx->extra_parse_data().payload.assign(ptr, size);
+ ptr += size;
}
} else {
ptr--;
@@ -627,6 +457,7 @@
auto res =
ParseField(tag, parent, ptr, end, containing_type, metadata, ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (res.second) break;
}
}
@@ -922,7 +753,6 @@
return target;
}
-
bool ExtensionSet::ParseFieldMaybeLazily(
int wire_type, int field_number, io::CodedInputStream* input,
ExtensionFinder* extension_finder,
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
new file mode 100644
index 0000000..93a0558
--- /dev/null
+++ b/src/google/protobuf/extension_set_inl.h
@@ -0,0 +1,244 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+
+#include <google/protobuf/extension_set.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+template <typename T>
+std::pair<const char*, bool> ExtensionSet::ParseFieldWithExtensionInfo(
+ int number, bool was_packed_on_wire, const ExtensionInfo& extension,
+ T* metadata, ParseClosure parent, const char* begin, const char* end,
+ internal::ParseContext* ctx) {
+ auto ptr = begin;
+ ParseClosure child;
+ int depth;
+ if (was_packed_on_wire) {
+ switch (extension.type) {
+#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \
+ case WireFormatLite::TYPE_##UPPERCASE: \
+ child = { \
+ internal::Packed##CPP_CAMELCASE##Parser, \
+ MutableRawRepeatedField(number, extension.type, extension.is_packed, \
+ extension.descriptor)}; \
+ goto length_delim
+ HANDLE_TYPE(INT32, Int32);
+ HANDLE_TYPE(INT64, Int64);
+ HANDLE_TYPE(UINT32, UInt32);
+ HANDLE_TYPE(UINT64, UInt64);
+ HANDLE_TYPE(SINT32, SInt32);
+ HANDLE_TYPE(SINT64, SInt64);
+ HANDLE_TYPE(FIXED32, Fixed32);
+ HANDLE_TYPE(FIXED64, Fixed64);
+ HANDLE_TYPE(SFIXED32, SFixed32);
+ HANDLE_TYPE(SFIXED64, SFixed64);
+ HANDLE_TYPE(FLOAT, Float);
+ HANDLE_TYPE(DOUBLE, Double);
+ HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+
+ case WireFormatLite::TYPE_ENUM:
+ ctx->extra_parse_data().SetEnumValidatorArg(
+ extension.enum_validity_check.func,
+ extension.enum_validity_check.arg,
+ metadata->mutable_unknown_fields(), number);
+ child = {
+ internal::PackedValidEnumParserLiteArg,
+ MutableRawRepeatedField(number, extension.type, extension.is_packed,
+ extension.descriptor)};
+ goto length_delim;
+ case WireFormatLite::TYPE_STRING:
+ case WireFormatLite::TYPE_BYTES:
+ case WireFormatLite::TYPE_GROUP:
+ case WireFormatLite::TYPE_MESSAGE:
+ GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+ break;
+ }
+ } else {
+ switch (extension.type) {
+#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \
+ case WireFormatLite::TYPE_##UPPERCASE: { \
+ uint64 value; \
+ ptr = Varint::Parse64(ptr, &value); \
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
+ if (extension.is_repeated) { \
+ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
+ extension.is_packed, value, extension.descriptor); \
+ } else { \
+ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
+ extension.descriptor); \
+ } \
+ } break
+
+ HANDLE_VARINT_TYPE(INT32, Int32);
+ HANDLE_VARINT_TYPE(INT64, Int64);
+ HANDLE_VARINT_TYPE(UINT32, UInt32);
+ HANDLE_VARINT_TYPE(UINT64, UInt64);
+#undef HANDLE_VARINT_TYPE
+#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \
+ case WireFormatLite::TYPE_##UPPERCASE: { \
+ uint64 val; \
+ ptr = Varint::Parse64(ptr, &val); \
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \
+ auto value = WireFormatLite::ZigZagDecode##SIZE(val); \
+ if (extension.is_repeated) { \
+ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
+ extension.is_packed, value, extension.descriptor); \
+ } else { \
+ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
+ extension.descriptor); \
+ } \
+ } break
+
+ HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
+ HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
+#undef HANDLE_SVARINT_TYPE
+#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \
+ case WireFormatLite::TYPE_##UPPERCASE: { \
+ CPPTYPE value; \
+ std::memcpy(&value, ptr, sizeof(CPPTYPE)); \
+ ptr += sizeof(CPPTYPE); \
+ if (extension.is_repeated) { \
+ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
+ extension.is_packed, value, extension.descriptor); \
+ } else { \
+ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
+ extension.descriptor); \
+ } \
+ } break
+
+ HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
+ HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
+ HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
+ HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
+ HANDLE_FIXED_TYPE(FLOAT, Float, float);
+ HANDLE_FIXED_TYPE(DOUBLE, Double, double);
+ HANDLE_FIXED_TYPE(BOOL, Bool, bool);
+#undef HANDLE_FIXED_TYPE
+
+ case WireFormatLite::TYPE_ENUM: {
+ uint64 val;
+ ptr = Varint::Parse64(ptr, &val);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ int value = val;
+
+ if (!extension.enum_validity_check.func(
+ extension.enum_validity_check.arg, value)) {
+ WriteVarint(number, val, metadata->mutable_unknown_fields());
+ } else if (extension.is_repeated) {
+ AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
+ extension.descriptor);
+ } else {
+ SetEnum(number, WireFormatLite::TYPE_ENUM, value,
+ extension.descriptor);
+ }
+ break;
+ }
+
+ case WireFormatLite::TYPE_BYTES:
+ case WireFormatLite::TYPE_STRING: {
+ std::string* value = extension.is_repeated
+ ? AddString(number, WireFormatLite::TYPE_STRING,
+ extension.descriptor)
+ : MutableString(number, WireFormatLite::TYPE_STRING,
+ extension.descriptor);
+ child = {StringParser, value};
+ goto length_delim;
+ }
+
+ case WireFormatLite::TYPE_GROUP: {
+ MessageLite* value =
+ extension.is_repeated
+ ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+ *extension.message_info.prototype,
+ extension.descriptor)
+ : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+ *extension.message_info.prototype,
+ extension.descriptor);
+ child = {extension.message_info.parse_func, value};
+ uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
+ auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
+ ptr = res.first;
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ if (res.second) {
+ GOOGLE_PROTOBUF_ASSERT_RETURN(
+ ctx->StoreGroup(parent, child, depth, tag),
+ std::make_pair(nullptr, true));
+ return std::make_pair(ptr, true);
+ }
+ break;
+ }
+
+ case WireFormatLite::TYPE_MESSAGE: {
+ MessageLite* value =
+ extension.is_repeated
+ ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+ *extension.message_info.prototype,
+ extension.descriptor)
+ : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+ *extension.message_info.prototype,
+ extension.descriptor);
+ child = {extension.message_info.parse_func, value};
+ goto length_delim;
+ }
+ }
+ }
+
+ return std::make_pair(ptr, false);
+
+length_delim:
+ uint32 size;
+ ptr = Varint::Parse32Inline(ptr, &size);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ if (size > end - ptr) goto len_delim_till_end;
+ {
+ auto newend = ptr + size;
+ bool ok = ctx->ParseExactRange(child, ptr, newend);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
+ ptr = newend;
+ }
+ return std::make_pair(ptr, false);
+len_delim_till_end:
+ return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
+ true);
+}
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index 8b25299..af51c07 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -68,15 +68,17 @@
file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
- false, InitDefaults_google_2fprotobuf_2ffield_5fmask_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto[] =
"\n google/protobuf/field_mask.proto\022\017goog"
"le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
"\214\001\n\023com.google.protobufB\016FieldMaskProtoP"
"\001Z9google.golang.org/genproto/protobuf/f"
"ield_mask;field_mask\370\001\001\242\002\003GPB\252\002\036Google.P"
"rotobuf.WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2ffield_5fmask_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
"google/protobuf/field_mask.proto", &assign_descriptors_table_google_2fprotobuf_2ffield_5fmask_2eproto, 230,
};
@@ -170,10 +172,10 @@
auto msg = static_cast<FieldMask*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -184,14 +186,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.FieldMask.paths");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->add_paths();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_paths();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
break;
@@ -199,13 +204,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -216,7 +221,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index 5b8561d..14a62d4 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -125,7 +125,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FieldMask& from);
void MergeFrom(const FieldMask& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/generated_message_table_driven.cc b/src/google/protobuf/generated_message_table_driven.cc
index d4450a6..b56f6b9 100644
--- a/src/google/protobuf/generated_message_table_driven.cc
+++ b/src/google/protobuf/generated_message_table_driven.cc
@@ -53,6 +53,10 @@
}
struct UnknownFieldHandler {
+ // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
+ // and conflating InternalMetaData into it, simplifying the template.
+ static constexpr bool IsLite() { return false; }
+
static bool Skip(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input,
int tag) {
diff --git a/src/google/protobuf/generated_message_table_driven_lite.cc b/src/google/protobuf/generated_message_table_driven_lite.cc
index 83c8180..892a1e6 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.cc
+++ b/src/google/protobuf/generated_message_table_driven_lite.cc
@@ -50,6 +50,10 @@
}
struct UnknownFieldHandlerLite {
+ // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
+ // and conflating InternalMetaData into it, simplifying the template.
+ static constexpr bool IsLite() { return true; }
+
static bool Skip(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input,
int tag) {
diff --git a/src/google/protobuf/generated_message_table_driven_lite.h b/src/google/protobuf/generated_message_table_driven_lite.h
index 17e256a..ea3d439 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.h
+++ b/src/google/protobuf/generated_message_table_driven_lite.h
@@ -222,16 +222,19 @@
}
}
-template <Cardinality cardinality, bool validate, StringType ctype>
+template <typename UnknownFieldHandler, Cardinality cardinality,
+ bool is_string_type, StringType ctype>
static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
Arena* arena, uint32* has_bits,
uint32 has_bit_index, int64 offset,
const void* default_ptr,
const char* field_name) {
+ StringPiece utf8_string_data;
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
- const char* sdata;
- size_t size;
-#endif
+ constexpr bool kValidateUtf8 = is_string_type;
+#else
+ constexpr bool kValidateUtf8 = false;
+#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
switch (ctype) {
case StringType_INLINED: {
@@ -251,55 +254,54 @@
}
GOOGLE_DCHECK(s != nullptr);
::std::string* value = s->MutableNoArena(NULL);
-
if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
return false;
}
-
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
- sdata = value->data();
- size = value->size();
-#endif
+ utf8_string_data = *value;
break;
}
case StringType_STRING: {
- std::string* value;
switch (cardinality) {
- case Cardinality_SINGULAR:
- // TODO(ckennelly): Is this optimal?
- value =
- MutableField<ArenaStringPtr>(msg, has_bits, has_bit_index, offset)
- ->Mutable(static_cast<const std::string*>(default_ptr), arena);
- break;
- case Cardinality_REPEATED:
- value = AddField<std::string>(msg, offset);
- break;
- case Cardinality_ONEOF:
- value = Raw<ArenaStringPtr>(msg, offset)
- ->Mutable(static_cast<const std::string*>(default_ptr), arena);
- break;
+ case Cardinality_SINGULAR: {
+ ArenaStringPtr* field = MutableField<ArenaStringPtr>(
+ msg, has_bits, has_bit_index, offset);
+ std::string* value =
+ field->Mutable(static_cast<const std::string*>(default_ptr), arena);
+ if (PROTOBUF_PREDICT_FALSE(
+ !WireFormatLite::ReadString(input, value))) {
+ return false;
+ }
+ utf8_string_data = field->Get();
+ } break;
+ case Cardinality_REPEATED: {
+ std::string* value = AddField<std::string>(msg, offset);
+ if (PROTOBUF_PREDICT_FALSE(
+ !WireFormatLite::ReadString(input, value))) {
+ return false;
+ }
+ utf8_string_data = *value;
+ } break;
+ case Cardinality_ONEOF: {
+ ArenaStringPtr* field = Raw<ArenaStringPtr>(msg, offset);
+ std::string* value =
+ field->Mutable(static_cast<const std::string*>(default_ptr), arena);
+ if (PROTOBUF_PREDICT_FALSE(
+ !WireFormatLite::ReadString(input, value))) {
+ return false;
+ }
+ utf8_string_data = field->Get();
+ } break;
}
- GOOGLE_DCHECK(value != nullptr);
-
- if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
- return false;
- }
-
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
- sdata = value->data();
- size = value->size();
-#endif
break;
}
}
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
- if (validate) {
- WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE,
- field_name);
+ if (kValidateUtf8) {
+ // TODO(b/118759213): fail if proto3
+ WireFormatLite::VerifyUtf8String(utf8_string_data.data(),
+ utf8_string_data.length(),
+ WireFormatLite::PARSE, field_name);
}
-#endif
-
return true;
}
@@ -371,9 +373,11 @@
}
};
-template <typename UnknownFieldHandler, typename InternalMetadata>
-bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
- io::CodedInputStream* input) {
+template <typename UnknownFieldHandler, typename InternalMetadata,
+ uint32 kMaxTag>
+bool MergePartialFromCodedStreamInlined(MessageLite* msg,
+ const ParseTable& table,
+ io::CodedInputStream* input) {
// We require that has_bits are present, as to avoid having to check for them
// for every field.
//
@@ -383,13 +387,12 @@
GOOGLE_DCHECK(has_bits != NULL);
while (true) {
- uint32 tag = input->ReadTag();
-
+ uint32 tag = input->ReadTagWithCutoffNoLastTag(kMaxTag).first;
const WireFormatLite::WireType wire_type =
WireFormatLite::GetTagWireType(tag);
const int field_number = WireFormatLite::GetTagFieldNumber(tag);
- if (field_number > table.max_field_number) {
+ if (PROTOBUF_PREDICT_FALSE(field_number > table.max_field_number)) {
// check for possible extensions
if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
// successfully parsed
@@ -476,16 +479,17 @@
case WireFormatLite::TYPE_BYTES:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING:
-#endif
+#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
- if (PROTOBUF_PREDICT_FALSE((
- !HandleString<Cardinality_SINGULAR, false, StringType_STRING>(
+ if (PROTOBUF_PREDICT_FALSE(
+ (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+ false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
- default_ptr, NULL)))) {
+ default_ptr, nullptr)))) {
return false;
}
break;
@@ -493,16 +497,17 @@
case TYPE_BYTES_INLINED:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED:
-#endif
+#endif // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
- if (PROTOBUF_PREDICT_FALSE((!HandleString<Cardinality_SINGULAR, false,
- StringType_INLINED>(
- input, msg, arena, has_bits, presence_index, offset,
- default_ptr, NULL)))) {
+ if (PROTOBUF_PREDICT_FALSE(
+ (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+ false, StringType_INLINED>(
+ input, msg, arena, has_bits, presence_index, offset,
+ default_ptr, nullptr)))) {
return false;
}
break;
@@ -510,7 +515,7 @@
case WireFormatLite::TYPE_BYTES | kOneofMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING | kOneofMask:
-#endif
+#endif // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
@@ -522,9 +527,10 @@
offset, default_ptr);
if (PROTOBUF_PREDICT_FALSE(
- (!HandleString<Cardinality_ONEOF, false, StringType_STRING>(
- input, msg, arena, has_bits, presence_index, offset,
- default_ptr, NULL)))) {
+ (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, false,
+ StringType_STRING>(input, msg, arena, has_bits,
+ presence_index, offset,
+ default_ptr, nullptr)))) {
return false;
}
break;
@@ -534,17 +540,18 @@
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
case TYPE_STRING_INLINED | kRepeatedMask:
-#endif
+#endif // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr =
table.aux[field_number].strings.default_ptr;
- if (PROTOBUF_PREDICT_FALSE((
- !HandleString<Cardinality_REPEATED, false, StringType_STRING>(
+ if (PROTOBUF_PREDICT_FALSE(
+ (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
+ false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
- default_ptr, NULL)))) {
+ default_ptr, nullptr)))) {
return false;
}
break;
@@ -557,7 +564,8 @@
const char* field_name = table.aux[field_number].strings.field_name;
if (PROTOBUF_PREDICT_FALSE(
- (!HandleString<Cardinality_SINGULAR, true, StringType_STRING>(
+ (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+ true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
@@ -572,7 +580,8 @@
const char* field_name = table.aux[field_number].strings.field_name;
if (PROTOBUF_PREDICT_FALSE(
- (!HandleString<Cardinality_REPEATED, true, StringType_STRING>(
+ (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
+ true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
@@ -591,14 +600,15 @@
offset, default_ptr);
if (PROTOBUF_PREDICT_FALSE(
- (!HandleString<Cardinality_ONEOF, true, StringType_STRING>(
+ (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, true,
+ StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
-#endif
+#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_ENUM: {
if (PROTOBUF_PREDICT_FALSE(
(!HandleEnum<UnknownFieldHandler, InternalMetadata,
@@ -735,8 +745,9 @@
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
- if (PROTOBUF_PREDICT_FALSE((
- !HandleString<Cardinality_SINGULAR, true, StringType_INLINED>(
+ if (PROTOBUF_PREDICT_FALSE(
+ (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+ true, StringType_INLINED>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
@@ -753,6 +764,7 @@
}
case 0: {
// Done.
+ input->SetLastTag(tag);
return true;
}
default:
@@ -847,6 +859,7 @@
} else {
if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
// Must be the end of the message.
+ input->SetLastTag(tag);
return true;
}
@@ -865,6 +878,26 @@
}
}
+template <typename UnknownFieldHandler, typename InternalMetadata>
+bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
+ io::CodedInputStream* input) {
+ // The main beneficial cutoff values are 1 and 2 byte tags.
+ // Instantiate calls with the appropriate upper tag range
+ if (table.max_field_number <= (0x7F >> 3)) {
+ return MergePartialFromCodedStreamInlined<UnknownFieldHandler,
+ InternalMetadata, 0x7F>(
+ msg, table, input);
+ } else if (table.max_field_number <= (0x3FFF >> 3)) {
+ return MergePartialFromCodedStreamInlined<UnknownFieldHandler,
+ InternalMetadata, 0x3FFF>(
+ msg, table, input);
+ } else {
+ return MergePartialFromCodedStreamInlined<
+ UnknownFieldHandler, InternalMetadata,
+ std::numeric_limits<uint32>::max()>(msg, table, input);
+ }
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index b9bbb26..ca6cc9c 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -46,6 +46,7 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/has_bits.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/map_entry_lite.h>
@@ -53,6 +54,7 @@
#include <google/protobuf/stubs/once.h> // Add direct dep on port for pb.cc
#include <google/protobuf/port.h>
#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>
@@ -60,11 +62,6 @@
#error "You cannot SWIG proto headers"
#endif
-#if GOOGLE_PROTOBUF_ENABLE_MOMI_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
-
namespace google {
namespace protobuf {
@@ -354,6 +351,32 @@
OnShutdownRun(DestroyString, ptr);
}
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
+inline void InlineGreedyStringParser(std::string* str, const char* begin, int size,
+ ParseContext*) {
+ str->assign(begin, size);
+}
+
+
+inline bool StringCheck(const char* begin, int size, ParseContext* ctx) {
+ return true;
+}
+
+inline bool StringCheckUTF8(const char* begin, int size, ParseContext* ctx) {
+ return VerifyUTF8(StringPiece(begin, size), ctx);
+}
+
+inline bool StringCheckUTF8Verify(const char* begin, int size,
+ ParseContext* ctx) {
+#ifndef NDEBUG
+ VerifyUTF8(StringPiece(begin, size), ctx);
+#endif
+ return true;
+}
+
+#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
index f924842..b26f441 100644
--- a/src/google/protobuf/implicit_weak_message.cc
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -30,15 +30,13 @@
#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index e893316..477b368 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -235,10 +235,10 @@
TestUtilLite::ExpectClear(message);
TestUtilLite::SetAllFields(&message);
data = message.SerializeAsString();
- empty_message.ParseFromString(data);
+ ASSERT_TRUE(empty_message.ParseFromString(data));
data.clear();
data = empty_message.SerializeAsString();
- message2.ParseFromString(data);
+ EXPECT_TRUE(message2.ParseFromString(data));
data = message2.SerializeAsString();
TestUtilLite::ExpectAllFieldsSet(message2);
message.Clear();
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 98b2aca..08a02ac 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -35,6 +35,7 @@
#include <string>
#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/map.h>
@@ -44,10 +45,6 @@
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
@@ -403,7 +400,7 @@
Metadata* metadata,
bool (*validate_enum)(int)) {
io::CodedInputStream input(reinterpret_cast<const uint8*>(begin),
- end - begin);
+ static_cast<int>(end - begin));
auto entry = NewEntry();
// TODO(gerbens) implement _InternalParse for maps. We can't use
// ParseFromString as this will call _InternalParse
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index 2ce54cb..7c10d67 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -162,6 +162,39 @@
return iter != map.end();
}
+void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
+ const FieldDescriptor* val_des =
+ default_entry_->GetDescriptor()->FindFieldByName("value");
+ map_val->SetType(val_des->cpp_type());
+ // Allocate memory for the MapValueRef, and initialize to
+ // default value.
+ switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
+ TYPE* value = new TYPE(); \
+ map_val->SetValue(value); \
+ break; \
+ }
+ HANDLE_TYPE(INT32, int32);
+ HANDLE_TYPE(INT64, int64);
+ HANDLE_TYPE(UINT32, uint32);
+ HANDLE_TYPE(UINT64, uint64);
+ HANDLE_TYPE(DOUBLE, double);
+ HANDLE_TYPE(FLOAT, float);
+ HANDLE_TYPE(BOOL, bool);
+ HANDLE_TYPE(STRING, string);
+ HANDLE_TYPE(ENUM, int32);
+#undef HANDLE_TYPE
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ const Message& message = default_entry_->GetReflection()->GetMessage(
+ *default_entry_, val_des);
+ Message* value = message.New();
+ map_val->SetValue(value);
+ break;
+ }
+ }
+}
+
bool DynamicMapField::InsertOrLookupMapValue(
const MapKey& map_key, MapValueRef* val) {
// Always use mutable map because users may change the map value by
@@ -169,38 +202,8 @@
Map<MapKey, MapValueRef>* map = MutableMap();
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter == map->end()) {
- // Insert
- MapValueRef& map_val = (*map)[map_key];
- const FieldDescriptor* val_des =
- default_entry_->GetDescriptor()->FindFieldByName("value");
- map_val.SetType(val_des->cpp_type());
- // Allocate memory for the inserted MapValueRef, and initialize to
- // default value.
- switch (val_des->cpp_type()) {
-#define HANDLE_TYPE(CPPTYPE, TYPE) \
- case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
- TYPE* value = new TYPE(); \
- map_val.SetValue(value); \
- break; \
- }
- HANDLE_TYPE(INT32, int32);
- HANDLE_TYPE(INT64, int64);
- HANDLE_TYPE(UINT32, uint32);
- HANDLE_TYPE(UINT64, uint64);
- HANDLE_TYPE(DOUBLE, double);
- HANDLE_TYPE(FLOAT, float);
- HANDLE_TYPE(BOOL, bool);
- HANDLE_TYPE(STRING, string);
- HANDLE_TYPE(ENUM, int32);
-#undef HANDLE_TYPE
- case FieldDescriptor::CPPTYPE_MESSAGE: {
- const Message& message = default_entry_->GetReflection()->GetMessage(
- *default_entry_, val_des);
- Message* value = message.New();
- map_val.SetValue(value);
- break;
- }
- }
+ MapValueRef& map_val = map_[map_key];
+ AllocateMapValue(&map_val);
val->CopyFrom(map_val);
return true;
}
@@ -243,6 +246,72 @@
map_iter->value_.CopyFrom(iter->second);
}
+void DynamicMapField::MergeFrom(const MapFieldBase& other) {
+ GOOGLE_DCHECK(IsMapValid() && other.IsMapValid());
+ Map<MapKey, MapValueRef>* map = MutableMap();
+ const DynamicMapField& other_field =
+ reinterpret_cast<const DynamicMapField&>(other);
+ for (typename Map<MapKey, MapValueRef>::const_iterator other_it =
+ other_field.map_.begin(); other_it != other_field.map_.end();
+ ++other_it) {
+ Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
+ MapValueRef* map_val;
+ if (iter == map->end()) {
+ map_val = &map_[other_it->first];
+ AllocateMapValue(map_val);
+ } else {
+ map_val = &iter->second;
+ }
+
+ // Copy map value
+ const FieldDescriptor* field_descriptor =
+ default_entry_->GetDescriptor()->FindFieldByName("value");
+ switch (field_descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32: {
+ map_val->SetInt32Value(other_it->second.GetInt32Value());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_INT64: {
+ map_val->SetInt64Value(other_it->second.GetInt64Value());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT32: {
+ map_val->SetUInt32Value(other_it->second.GetUInt32Value());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ map_val->SetUInt64Value(other_it->second.GetUInt64Value());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ map_val->SetFloatValue(other_it->second.GetFloatValue());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ map_val->SetDoubleValue(other_it->second.GetDoubleValue());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_BOOL: {
+ map_val->SetBoolValue(other_it->second.GetBoolValue());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING: {
+ map_val->SetStringValue(other_it->second.GetStringValue());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ map_val->SetEnumValue(other_it->second.GetEnumValue());
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ map_val->MutableMessageValue()->CopyFrom(
+ other_it->second.GetMessageValue());
+ break;
+ }
+ }
+ }
+}
+
void DynamicMapField::Swap(MapFieldBase* other) {
DynamicMapField* other_field = down_cast<DynamicMapField*>(other);
std::swap(this->MapFieldBase::repeated_field_, other_field->repeated_field_);
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 38dd35d..bba5d8a 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -103,6 +103,7 @@
const MapIterator& b) const = 0;
virtual void MapBegin(MapIterator* map_iter) const = 0;
virtual void MapEnd(MapIterator* map_iter) const = 0;
+ virtual void MergeFrom(const MapFieldBase& other) = 0;
virtual void Swap(MapFieldBase* other) = 0;
// Sync Map with repeated field and returns the size of map.
virtual int size() const = 0;
@@ -270,7 +271,7 @@
// Convenient methods for generated message implementation.
int size() const override;
void Clear();
- void MergeFrom(const MapField& other);
+ void MergeFrom(const MapFieldBase& other) override;
void Swap(MapFieldBase* other) override;
// Used in the implementation of parsing. Caller should take the ownership iff
@@ -326,6 +327,7 @@
bool ContainsMapKey(const MapKey& map_key) const override;
bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
bool DeleteMapValue(const MapKey& map_key) override;
+ void MergeFrom(const MapFieldBase& other) override;
void Swap(MapFieldBase* other) override;
const Map<MapKey, MapValueRef>& GetMap() const override;
@@ -337,6 +339,8 @@
Map<MapKey, MapValueRef> map_;
const Message* default_entry_;
+ void AllocateMapValue(MapValueRef* map_val);
+
// Implements MapFieldBase
void SyncRepeatedFieldWithMapNoLock() const override;
void SyncMapWithRepeatedFieldNoLock() const override;
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index 0e78342..73c16ed 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -242,10 +242,11 @@
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
- default_enum_value>::MergeFrom(const MapField& other) {
+ default_enum_value>::MergeFrom(const MapFieldBase& other) {
MapFieldBase::SyncMapWithRepeatedField();
- other.SyncMapWithRepeatedField();
- impl_.MergeFrom(other.impl_);
+ const MapField& other_field = static_cast<const MapField&>(other);
+ other_field.SyncMapWithRepeatedField();
+ impl_.MergeFrom(other_field.impl_);
MapFieldBase::SetMapDirty();
}
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index dcfcca7..ae7bd58 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -96,6 +96,7 @@
int size() const { return 0; }
void MapBegin(MapIterator* map_iter) const {}
void MapEnd(MapIterator* map_iter) const {}
+ void MergeFrom(const MapFieldBase& other) override {}
void Swap(MapFieldBase* other) {}
void InitializeIterator(MapIterator* map_iter) const {}
void DeleteIterator(MapIterator* map_iter) const {}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 080b9df..41d9c37 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -2032,6 +2032,31 @@
MapTestUtil::ExpectMapFieldsSet(message2);
}
+TEST(GeneratedMapFieldTest, DynamicMessageMergeFromDynamicMessage) {
+ // Construct two dynamic message and sets via map reflection.
+ DynamicMessageFactory factory;
+ std::unique_ptr<Message> message1;
+ message1.reset(
+ factory.GetPrototype(unittest::TestMap::descriptor())->New());
+ MapReflectionTester reflection_tester(
+ unittest::TestMap::descriptor());
+ reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+
+ std::unique_ptr<Message> message2;
+ message2.reset(
+ factory.GetPrototype(unittest::TestMap::descriptor())->New());
+ reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+ message2->MergeFrom(*message1);
+
+ // Test MergeFrom does not sync to repeated fields and
+ // there is no duplicate keys in text format.
+ string output1, output2;
+ TextFormat::PrintToString(*message1, &output1);
+ TextFormat::PrintToString(*message2, &output2);
+ EXPECT_EQ(output1, output2);
+}
+
TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
// Test copying to a DynamicMessage, which must fall back to using reflection.
unittest::TestMap message2;
@@ -2097,6 +2122,18 @@
message1.MergeFrom(message2);
MapTestUtil::ExpectMapFieldsSet(message1);
+
+ // Test reflection MergeFrom does not sync to repeated field
+ // and there is no duplicated keys.
+ MapTestUtil::SetMapFields(&message1);
+ MapTestUtil::SetMapFields(&message2);
+
+ message2.MergeFrom(message1);
+
+ string output1, output2;
+ TextFormat::PrintToString(message1, &output1);
+ TextFormat::PrintToString(message2, &output2);
+ EXPECT_EQ(output1, output2);
}
TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 5a9acaf..fc307f0 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -43,6 +43,7 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/reflection_internal.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -51,6 +52,7 @@
#include <google/protobuf/map_field.h>
#include <google/protobuf/map_field_inl.h>
#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/stubs/strutil.h>
@@ -309,15 +311,12 @@
}
ParseClosure GetLenDelim(int field_number, const FieldDescriptor* field,
- Message* msg, UnknownFieldSet* unknown,
- const Reflection* reflection,
+ Message* msg, const Reflection* reflection,
internal::ParseContext* ctx) {
- if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) !=
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
- if (field && field->is_packable()) {
- return GetPackedField(field, msg, reflection, ctx);
- }
- return {internal::StringParser, unknown->AddLengthDelimited(field_number)};
+ if (WireFormat::WireTypeForFieldType(field->type()) !=
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ ABSL_ASSERT(field->is_packable());
+ return GetPackedField(field, msg, reflection, ctx);
}
enum { kNone = 0, kVerify, kStrict } utf8_level = kNone;
internal::ParseFunc string_parsers[] = {internal::StringParser,
@@ -402,77 +401,8 @@
}
}
-const char* ReflectiveParseMessageSetItem(const char* begin, const char* end,
- void* object,
- internal::ParseContext* ctx) {
- ParseClosure child;
- auto msg = static_cast<Message*>(object);
- auto reflection = msg->GetReflection();
- uint32 size;
- auto ptr = begin;
- while (ptr < end) {
- uint32 tag = *ptr++;
- if (tag == WireFormatLite::kMessageSetTypeIdTag) {
- uint32 type_id;
- ptr = Varint::Parse32(ptr, &type_id);
- if (!ptr) goto error;
-
- auto field = reflection->FindKnownExtensionByNumber(type_id);
-
- if (ctx->extra_parse_data().payload.empty()) {
- tag = *ptr++;
- if (tag == WireFormatLite::kMessageSetMessageTag) {
- ptr = Varint::Parse32Inline(ptr, &size);
- if (!ptr) goto error;
- child = GetLenDelim(type_id * 8 + 2, field, msg,
- reflection->MutableUnknownFields(msg), reflection,
- ctx);
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
- ptr = newend;
- } else {
- goto error;
- }
- } else {
- GOOGLE_LOG(FATAL) << "Wrong order";
- }
- } else if (tag == WireFormatLite::kMessageSetItemEndTag) {
- if (!ctx->ValidEndGroup(tag)) goto error;
- break;
- } else if (tag == WireFormatLite::kMessageSetMessageTag) {
- uint32 size;
- ptr = Varint::Parse32Inline(ptr, &size);
- if (!ptr) goto error;
- child = {internal::StringParser, &ctx->extra_parse_data().payload};
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
- ptr = newend;
- } else {
- GOOGLE_LOG(FATAL) << "Unknown message set item tag";
- }
- }
- return ptr;
-error:
- return nullptr;
-len_delim_till_end:
- return ctx->StoreAndTailCall(ptr, end, {ReflectiveParseMessageSetItem, msg},
- child, size);
-}
-
ParseClosure GetGroup(int field_number, const FieldDescriptor* field,
- Message* msg, UnknownFieldSet* unknown,
- const Reflection* reflection) {
- if (field == nullptr && field_number == 1 &&
- msg->GetDescriptor()->options().message_set_wire_format()) {
- return {ReflectiveParseMessageSetItem, msg};
- }
- if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) !=
- WireFormatLite::WIRETYPE_START_GROUP) {
- return {internal::UnknownGroupParse, unknown->AddGroup(field_number)};
- }
-
+ Message* msg, const Reflection* reflection) {
Message* object;
if (field->is_repeated()) {
object = reflection->AddMessage(msg, field, nullptr);
@@ -484,125 +414,147 @@
const char* Message::_InternalParse(const char* begin, const char* end,
void* object, internal::ParseContext* ctx) {
- auto msg = static_cast<Message*>(object);
- const Descriptor* descriptor = msg->GetDescriptor();
- const Reflection* reflection = msg->GetReflection();
- auto unknown = reflection->MutableUnknownFields(msg);
- GOOGLE_DCHECK(descriptor);
- GOOGLE_DCHECK(reflection);
+ class ReflectiveFieldParser {
+ public:
+ ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx)
+ : ReflectiveFieldParser(msg, ctx, false) {}
- GOOGLE_DCHECK(begin <= end);
- uint32 size;
- internal::ParseFunc parser_till_end;
- uint32 tag;
- int depth;
- auto ptr = begin;
- while (ptr < end) {
- ptr = Varint::Parse32Inline(ptr, &tag);
- if (ptr == nullptr) return nullptr;
- if (tag == 0) {
- if (ctx->ValidEndGroup(0)) return ptr;
- return nullptr;
- }
- if ((tag >> 3) == 0) return nullptr;
- const FieldDescriptor* field = nullptr;
-
- int field_number = WireFormatLite::GetTagFieldNumber(tag);
- field = descriptor->FindFieldByNumber(field_number);
-
- // If that failed, check if the field is an extension.
- if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
- auto pool = ctx->extra_parse_data().pool;
- if (pool == NULL) {
- field = reflection->FindKnownExtensionByNumber(field_number);
+ void AddVarint(uint32 num, uint64 value) {
+ if (is_item_ && num == 2) {
+ if (!ctx_->extra_parse_data().payload.empty()) {
+ auto field = Field(value, 2);
+ if (field && field->message_type()) {
+ auto child = reflection_->MutableMessage(msg_, field);
+ // TODO(gerbens) signal error
+ child->ParsePartialFromString(ctx_->extra_parse_data().payload);
+ } else {
+ MutableUnknown()->AddLengthDelimited(value)->swap(
+ ctx_->extra_parse_data().payload);
+ }
+ return;
+ }
+ ctx_->extra_parse_data().field_number = value;
+ return;
+ }
+ auto field = Field(num, 0);
+ if (field) {
+ SetField(value, field, msg_, reflection_);
} else {
- field = pool->FindExtensionByNumber(descriptor, field_number);
+ MutableUnknown()->AddVarint(num, value);
+ }
+ }
+ void AddFixed64(uint32 num, uint64 value) {
+ auto field = Field(num, 1);
+ if (field) {
+ SetField(value, field, msg_, reflection_);
+ } else {
+ MutableUnknown()->AddFixed64(num, value);
+ }
+ }
+ ParseClosure AddLengthDelimited(uint32 num, uint32) {
+ if (is_item_ && num == 3) {
+ int type_id = ctx_->extra_parse_data().field_number;
+ if (type_id == 0) {
+ return {internal::StringParser, &ctx_->extra_parse_data().payload};
+ }
+ ctx_->extra_parse_data().field_number = 0;
+ num = type_id;
+ }
+ auto field = Field(num, 2);
+ if (field) {
+ return GetLenDelim(num, field, msg_, reflection_, ctx_);
+ } else {
+ return {internal::StringParser,
+ MutableUnknown()->AddLengthDelimited(num)};
+ }
+ }
+ ParseClosure StartGroup(uint32 num) {
+ if (!is_item_ && descriptor_->options().message_set_wire_format() &&
+ num == 1) {
+ ctx_->extra_parse_data().payload.clear();
+ ctx_->extra_parse_data().field_number = 0;
+ return {ItemParser, msg_};
+ }
+ auto field = Field(num, 3);
+ if (field) {
+ return GetGroup(num, field, msg_, reflection_);
+ } else {
+ return {internal::UnknownGroupParse, MutableUnknown()->AddGroup(num)};
+ }
+ }
+ void EndGroup(uint32 num) {}
+ void AddFixed32(uint32 num, uint32 value) {
+ auto field = Field(num, 5);
+ if (field) {
+ SetField(value, field, msg_, reflection_);
+ } else {
+ MutableUnknown()->AddFixed32(num, value);
}
}
- switch (tag & 7) {
- case 0: {
- uint64 val;
- ptr = Varint::Parse64(ptr, &val);
- if (!ptr) goto error;
- if (field == nullptr ||
- WireFormat::WireTypeForFieldType(field->type()) != 0) {
- unknown->AddVarint(field_number, val);
- break;
- }
- SetField(val, field, msg, reflection);
- break;
- }
- case 1: {
- uint64 val = UNALIGNED_LOAD64(ptr);
- ptr = ptr + 8;
- if (field == nullptr ||
- WireFormat::WireTypeForFieldType(field->type()) != 1) {
- unknown->AddFixed64(field_number, val);
- break;
- }
- SetField(val, field, msg, reflection);
- break;
- }
- case 2: {
- ptr = Varint::Parse32Inline(ptr, &size);
- if (!ptr) goto error;
- ParseClosure child =
- GetLenDelim(field_number, field, msg, unknown, reflection, ctx);
- parser_till_end = child.func;
- object = child.object;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
- ptr = newend;
- break;
- }
- case 3: {
- if (!ctx->PrepareGroup(tag, &depth)) goto error;
+ private:
+ Message* msg_;
+ const Descriptor* descriptor_;
+ const Reflection* reflection_;
+ internal::ParseContext* ctx_;
+ UnknownFieldSet* unknown_ = nullptr;
+ bool is_item_ = false;
- ParseClosure child =
- GetGroup(field_number, field, msg, unknown, reflection);
- parser_till_end = child.func;
- object = child.object;
-
- if (ptr < end) ptr = child(ptr, end, ctx);
- if (!ptr) goto error;
- if (ctx->GroupContinues(depth)) goto group_continues;
- break;
- }
- case 4: {
- if (!ctx->ValidEndGroup(tag)) goto error;
- return ptr;
- }
- case 5: {
- uint32 val = UNALIGNED_LOAD32(ptr);
- ptr = ptr + 4;
- if (field == nullptr ||
- WireFormat::WireTypeForFieldType(field->type()) != 5) {
- unknown->AddFixed32(field_number, val);
- break;
- }
- SetField(val, field, msg, reflection);
- break;
- }
- default:
- goto error;
+ ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx,
+ bool is_item)
+ : msg_(msg),
+ descriptor_(msg->GetDescriptor()),
+ reflection_(msg->GetReflection()),
+ ctx_(ctx),
+ is_item_(is_item) {
+ GOOGLE_CHECK(descriptor_) << typeid(*this).name();
+ GOOGLE_CHECK(reflection_) << descriptor_->name() << " " << typeid(*this).name();
}
- }
- return ptr;
-error:
- return nullptr;
-len_delim_till_end:
- // Length delimited field crosses end
- return ctx->StoreAndTailCall(ptr, end, {Message::_InternalParse, msg},
- {parser_till_end, object}, size);
-group_continues:
- GOOGLE_DCHECK(ptr >= end);
- // Group crossed end and must be continued. Either this a parse failure
- // or we need to resume on the next chunk and thus save the state.
- ctx->StoreGroup({Message::_InternalParse, msg}, {parser_till_end, object},
- depth);
- return ptr;
+
+ const FieldDescriptor* Field(int num, int wire_type) {
+ auto field = descriptor_->FindFieldByNumber(num);
+
+ // If that failed, check if the field is an extension.
+ if (field == nullptr && descriptor_->IsExtensionNumber(num)) {
+ const DescriptorPool* pool = ctx_->extra_parse_data().pool;
+ if (pool == NULL) {
+ field = reflection_->FindKnownExtensionByNumber(num);
+ } else {
+ field = pool->FindExtensionByNumber(descriptor_, num);
+ }
+ }
+ if (field == nullptr) return nullptr;
+
+ if (internal::WireFormat::WireTypeForFieldType(field->type()) !=
+ wire_type) {
+ if (field->is_packable()) {
+ if (wire_type ==
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ return field;
+ }
+ }
+ return nullptr;
+ }
+ return field;
+ }
+
+ UnknownFieldSet* MutableUnknown() {
+ if (unknown_) return unknown_;
+ return unknown_ = reflection_->MutableUnknownFields(msg_);
+ }
+
+ static const char* ItemParser(const char* begin, const char* end,
+ void* object, internal::ParseContext* ctx) {
+ auto msg = static_cast<Message*>(object);
+ ReflectiveFieldParser field_parser(msg, ctx, true);
+ return internal::WireFormatParser({ItemParser, object}, field_parser,
+ begin, end, ctx);
+ }
+ };
+
+ ReflectiveFieldParser field_parser(static_cast<Message*>(object), ctx);
+ return internal::WireFormatParser({_InternalParse, object}, field_parser,
+ begin, end, ctx);
}
#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 9f44132..0734df5 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -201,7 +201,7 @@
class PROTOBUF_EXPORT Message : public MessageLite {
public:
inline Message() {}
- virtual ~Message() {}
+ ~Message() override {}
// Basic Operations ------------------------------------------------
@@ -436,15 +436,12 @@
// Get the UnknownFieldSet for the message. This contains fields which
// were seen when the Message was parsed but were not recognized according
- // to the Message's definition. For proto3 protos, this method will always
- // return an empty UnknownFieldSet.
+ // to the Message's definition.
virtual const UnknownFieldSet& GetUnknownFields(
const Message& message) const = 0;
// Get a mutable pointer to the UnknownFieldSet for the message. This
// contains fields which were seen when the Message was parsed but were not
- // recognized according to the Message's definition. For proto3 protos, this
- // method will return a valid mutable UnknownFieldSet pointer but modifying
- // it won't affect the serialized bytes of the message.
+ // recognized according to the Message's definition.
virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
// Estimate the amount of memory used by the message object.
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 01bb0d3..8edae78 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -39,22 +39,19 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#include "util/utf8/public/unilib.h"
-#include "util/utf8/public/unilib_utf8_utils.h"
-#endif
-
namespace google {
namespace protobuf {
@@ -106,376 +103,149 @@
return result;
}
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-// This is wrapper to turn a ZeroCopyInputStream (ZCIS) into a
-// InputStreamWithOverlap. This is done by copying data around the seams,
-// hence the name EpsCopyInputStream, pictorially if ZCIS presents a stream
-// in chunks like so
-// [---------------------------------------------------------------]
-// [---------------------] chunk 1
-// [----------------------------] chunk 2
-// chunk 3 [--------------]
-// where '-' depicts bytes of the stream or chunks vertically alligned with the
-// corresponding bytes between stream and chunk.
-//
-// This class will convert this into chunks
-// [-----------------....] chunk 1
-// [----....] patch
-// [------------------------....] chunk 2
-// [----....] patch
-// chunk 3 [----------....]
-// patch [----****]
-// by using a fixed size buffer to patch over the seams. This requires
-// copying of an "epsilon" neighboorhood around the seams. In the picture above
-// dots mean bytes beyond the end of the new chunks. Each chunk is kSlopBytes
-// smalller as its original chunk (above depicted as 4 dots) and the number of
-// of chunks is doubled because each seam in the original stream introduces a
-// new patch.
-//
-// The algorithm is simple but not entirely trivial. Two complications arise
-// 1) The original chunk could be less than kSlopBytes. Hence we can't simply
-// chop the last kSlopBytes of a chunk.
-// 2) We need to leave the underlying CodedInputStream (CIS) precisely at the
-// last byte read in the parse. In most cases a parse ends on a limit or end of
-// the ZeroCopyInputStream, which is not problematic because CIS will never give
-// us data beyond that. But the parse can end on a 0 end tag or an end group.
-// If that happens in the first kSlopBytes of the patch (which are copied
-// from the previous buffer) the CIS has already moved to the next chunk to
-// copy the remaining bytes of the patch buffer. There exist no API to rollback
-// to a previous buffer.
-//
-// We model this as a state machine. A call to get the next chunk either returns
-// an original chunk except the last kSlopBytes or it has to copy the last
-// kSlopBytes of the current chunk to the patch buffer and copy the first
-// kSlopBytes of the next chunk to the end of the patch buffer.
-//
-// In order to deal with problem 1, we need to deal with the case that a new
-// chunk can be less or equal than kSlopBytes big. We can just copy the chunk
-// to the end and return (buffer, chunk->size). Pictorially
-// [--------] chunk 1
-// [--] chunk 2
-// [---] chunk 3
-// will become
-// [----....] chunk 1
-// [--....] patch (not full range of the buffer, only two hyphens)
-// [--] chunk 2 (too small so never returned as buffer)
-// [---....] patch (not full range of the buffer, only three hyphens)
-// [---] chunk 3 (too small so never returned as buffer)
-// [----****] patch (full range, last bytes are garbage)
-// Because of this the source (the dots in above) can overlap with the
-// destination buffer and so we have to use memmove.
-//
-// To solve problem 2, we verify after copying the last kSlopBytes the parse
-// won't end before we continue to get the next chunk.
-template <int kSlopBytes>
-class EpsCopyInputStream {
- public:
- EpsCopyInputStream(io::CodedInputStream* input) : input_(input) {}
- ~EpsCopyInputStream() {
- ABSL_ASSERT(skip_ >= 0);
- input_->Skip(skip_);
- }
-
- template <typename EnsureNotEnd>
- StringPiece SafeNextWithOverlap(const EnsureNotEnd& ensure_not_end) {
- switch (next_state_) {
- case kEOS:
- // End of stream
- return nullptr;
- case kChunk:
- // chunk_ contains a buffer of sufficient size (> kSlopBytes).
- // To parse the last kSlopBytes we need to copy the bytes into the
- // buffer. Hence we set,
- next_state_ = kBuffer;
- skip_ = chunk_.size() - kSlopBytes;
- return {chunk_.begin(), chunk_.size() - kSlopBytes};
- case kBuffer: {
- // We have to parse the last kSlopBytes of chunk_, which could alias
- // buffer_ so we have to memmove.
- std::memmove(buffer_, chunk_.end() - kSlopBytes, kSlopBytes);
- skip_ += kSlopBytes;
- // We need to fill in the other half of buffer_ with the start of the
- // next chunk. So we need to continue to the next buffer in the ZCIS,
- // which makes it impossible to rollback to the current buffer :(
- // We need to verify this won't happen.
- if (!ensure_not_end(buffer_, kSlopBytes)) {
- // We are guaranteed to exit in this interval.
- next_state_ = kEOS;
- return {buffer_, kSlopBytes};
- }
- chunk_ = GetChunk();
- auto size = chunk_.size();
- if (size > kSlopBytes) {
- next_state_ = kChunk;
- std::memcpy(buffer_ + kSlopBytes, chunk_.begin(), kSlopBytes);
- return {buffer_, kSlopBytes};
- } else if (size == 0) {
- next_state_ = kEOS;
- return {buffer_, kSlopBytes};
- } else {
- // next_state_ = kBuffer, but this is unnecessary
-
- // The next chunk is not big enough. So we copy it in the current
- // after the current buffer. Resulting in a buffer with
- // size + kSlopBytes bytes.
- std::memcpy(buffer_ + kSlopBytes, chunk_.begin(), size);
- // skip_ becomes negative here.
- skip_ += size - kSlopBytes;
- chunk_ = {buffer_, size + kSlopBytes};
- return {buffer_, size};
- }
- }
- case kStart: {
- chunk_ = GetChunk();
- auto size = chunk_.size();
- if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
- next_state_ = kBuffer;
- skip_ = size - kSlopBytes;
- return {chunk_.begin(), size - kSlopBytes};
- }
- size_t i = 0;
- do {
- if (size == 0) {
- next_state_ = kEOS;
- return {buffer_, i};
- }
- std::memcpy(buffer_ + i, chunk_.begin(), size);
- ABSL_ASSERT(skip_ == 0);
- skip_ = size;
- i += size;
- if (i > kSlopBytes) {
- skip_ -= kSlopBytes;
- chunk_ = {buffer_, i};
- next_state_ = kBuffer;
- return {buffer_, i - kSlopBytes};
- }
- if (!ensure_not_end(buffer_, i)) {
- next_state_ = kEOS;
- return {buffer_, i};
- }
- chunk_ = GetChunk();
- size = chunk_.size();
- } while (size <= kSlopBytes);
- std::memcpy(buffer_ + i, chunk_.begin(), kSlopBytes);
- next_state_ = kChunk;
- return {buffer_, i};
- }
- }
- }
-
- StringPiece NextWithOverlap() {
- return SafeNextWithOverlap([](const char*, size_t) { return true; });
- }
-
- void AdjustPos(int delta) {
- ABSL_ASSERT(delta <= kSlopBytes);
- skip_ += delta;
- }
-
- void SetError() { skip_ = 0; }
-
- private:
- io::CodedInputStream* input_;
- StringPiece chunk_;
- char buffer_[2 * kSlopBytes] = {};
- enum State {
- kStart,
- kEOS, // -> end of stream.
- kChunk, // -> chunk_ contains the data for Next.
- kBuffer, // -> We need to copy the left over from previous chunk_ and
- // load and patch the start of the next chunk in the
- // local buffer.
- };
- State next_state_ = kStart;
- int skip_ = 0; // how much bytes to skip to current position in the stream.
-
- StringPiece GetChunk() {
- const void* ptr;
- ABSL_ASSERT(skip_ >= 0);
- input_->Skip(skip_);
- skip_ = 0;
- int size;
- if (!input_->GetDirectBufferPointer(&ptr, &size)) {
- return nullptr;
- }
- return StringPiece(static_cast<const char*>(ptr), size);
- }
-};
-#endif
-
-// Several of the Parse methods below just do one thing and then call another
-// method. In a naive implementation, we might have ParseFromString() call
-// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
-// ParseFromCodedStream() which would call MergeFromCodedStream() which would
-// call MergePartialFromCodedStream(). However, when parsing very small
-// messages, every function call introduces significant overhead. To avoid
-// this without reproducing code, we use these forced-inline helpers.
-
-inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
- MessageLite* message) {
- if (!message->MergePartialFromCodedStream(input)) return false;
- if (!message->IsInitialized()) {
- GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
- return false;
- }
- return true;
-}
-
-inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
- MessageLite* message) {
- message->Clear();
- return message->MergePartialFromCodedStream(input);
-}
-
-inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
- MessageLite* message) {
- message->Clear();
- return InlineMergeFromCodedStream(input, message);
-}
-
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-template <template <int> class Input>
-inline bool InlineMergePartialEntireInput(
- Input<internal::ParseContext::kSlopBytes>* input, MessageLite* message) {
- internal::ParseContext ctx;
-
- auto chunk = input->NextWithOverlap();
- if (chunk.empty()) {
- return true;
- }
- auto res = ctx.StartParse({message->_ParseFunc(), message}, chunk);
- while (res.first == internal::ParseContext::kContinue) {
- int overrun = res.second;
- chunk = input->NextWithOverlap();
- if (chunk.empty()) {
- if (!ctx.ValidEnd(overrun)) return false;
- return true;
- }
- res = ctx.ResumeParse(chunk, overrun);
- }
- // Either failure or ended on a zero or end-group tag
- return false;
-}
-#endif
-
-inline bool InlineMergePartialEntireStream(io::CodedInputStream* cis,
- MessageLite* message) {
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
- EpsCopyInputStream<internal::ParseContext::kSlopBytes> input(cis);
- if (InlineMergePartialEntireInput(&input, message)) {
- cis->SetConsumed();
- return true;
- }
- return false;
-#else
- return message->MergePartialFromCodedStream(cis) &&
- cis->ConsumedEntireMessage();
-#endif
-}
-
-inline bool InlineMergeEntireStream(io::CodedInputStream* input,
- MessageLite* message) {
- if (!InlineMergePartialEntireStream(input, message)) return false;
- if (!message->IsInitialized()) {
- GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
- return false;
- }
- return true;
-}
-
-inline bool InlineParsePartialEntireStream(io::CodedInputStream* input,
- MessageLite* message) {
- message->Clear();
- return InlineMergePartialEntireStream(input, message);
-}
-
-inline bool InlineParseEntireStream(io::CodedInputStream* input,
- MessageLite* message) {
- message->Clear();
- return InlineMergeEntireStream(input, message);
-}
-
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-template <int kSlopBytes>
-class ArrayInput {
- public:
- ArrayInput(StringPiece chunk) : chunk_(chunk) {}
-
- StringPiece NextWithOverlap() {
- auto s = chunk_.size();
- if (s > 16) {
- auto res = chunk_.substr(0, s - 16);
- chunk_ = chunk_.substr(s - 16);
- return res;
- } else if (s == 0) {
- return nullptr;
- } else {
- std::memcpy(buffer_, chunk_.begin(), s);
- chunk_ = nullptr;
- return {buffer_, s};
- }
- }
-
- void SetError() {}
-
- private:
- StringPiece chunk_;
- char buffer_[32] = {};
- int state_ = 0;
-};
-#endif
-
-inline bool InlineMergePartialFromArray(const void* data, int size,
- MessageLite* msg,
- bool aliasing = false) {
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
- auto begin = static_cast<const char*>(data);
- if (aliasing) {
- // TODO(gerbens) make this safe against corruption buffer overflow.
- // Short cut to allow aliasing string_piece
- internal::ParseContext ctx;
- ctx.extra_parse_data().aliasing = true;
- return ctx.ParseExactRange({msg->_ParseFunc(), msg}, begin, begin + size);
- }
- ArrayInput<internal::ParseContext::kSlopBytes> input(
- StringPiece(begin, size));
- return InlineMergePartialEntireInput(&input, msg);
-#else
- io::CodedInputStream input(static_cast<const uint8*>(data), size);
- return msg->MergePartialFromCodedStream(&input) &&
- input.ConsumedEntireMessage();
-#endif
-}
-
-inline bool InlineMergeFromArray(const void* data, int size,
- MessageLite* message, bool aliasing = false) {
- if (!InlineMergePartialFromArray(data, size, message, aliasing)) return false;
- if (!message->IsInitialized()) {
- GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
- return false;
- }
- return true;
-}
-
-inline bool InlineParsePartialFromArray(const void* data, int size,
- MessageLite* message,
- bool aliasing = false) {
- message->Clear();
- return InlineMergePartialFromArray(data, size, message, aliasing);
-}
-
-inline bool InlineParseFromArray(const void* data, int size,
- MessageLite* message, bool aliasing = false) {
- if (!InlineParsePartialFromArray(data, size, message, aliasing)) return false;
- if (!message->IsInitialized()) {
- GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
- return false;
- }
- return true;
+inline StringPiece as_string_view(const void* data, int size) {
+ return StringPiece(static_cast<const char*>(data), size);
}
} // namespace
+void MessageLite::LogInitializationErrorMessage() const {
+ GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+}
+
+namespace internal {
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+template <typename Next>
+bool ParseStream(const Next& next, MessageLite* msg) {
+ internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
+ EpsCopyParser<false> parser({msg->_ParseFunc(), msg}, &ctx);
+ auto range = next();
+ while (!range.empty()) {
+ if (!parser.Parse(range)) return false;
+ range = next();
+ }
+ return parser.Done();
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg) {
+ auto begin = input.data();
+ int size = input.size();
+ ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
+ internal::ParseClosure parser = {msg->_ParseFunc(), msg};
+ // TODO(gerbens) fine tune
+ constexpr int kThreshold = 48;
+ static_assert(kThreshold >= ParseContext::kSlopBytes,
+ "Requires enough room for at least kSlopBytes to be copied.");
+ // TODO(gerbens) This could be left uninitialized and given an MSAN
+ // annotation instead.
+ char buffer[kThreshold + ParseContext::kSlopBytes] = {};
+ if (size <= kThreshold) {
+ std::memcpy(buffer, begin, size);
+ if (aliasing) {
+ ctx.extra_parse_data().aliasing =
+ reinterpret_cast<std::uintptr_t>(begin) -
+ reinterpret_cast<std::uintptr_t>(buffer);
+ }
+ return ctx.ParseExactRange(parser, buffer, buffer + size);
+ }
+ if (aliasing) {
+ ctx.extra_parse_data().aliasing = ParseContext::ExtraParseData::kNoDelta;
+ }
+ size -= ParseContext::kSlopBytes;
+ int overrun = 0;
+ ctx.StartParse(parser);
+ if (!ctx.ParseRange(StringPiece(begin, size), &overrun)) return false;
+ begin += size;
+ std::memcpy(buffer, begin, ParseContext::kSlopBytes);
+ if (aliasing) {
+ ctx.extra_parse_data().aliasing = reinterpret_cast<std::uintptr_t>(begin) -
+ reinterpret_cast<std::uintptr_t>(buffer);
+ }
+ return ctx.ParseRange({buffer, ParseContext::kSlopBytes}, &overrun) &&
+ ctx.ValidEnd(overrun);
+}
+
+StringPiece Next(BoundedZCIS* input) {
+ const void* data;
+ int size;
+ if (input->limit == 0) return {};
+ while (input->zcis->Next(&data, &size)) {
+ if (size != 0) {
+ input->limit -= size;
+ if (input->limit < 0) {
+ size += input->limit;
+ input->zcis->BackUp(-input->limit);
+ input->limit = 0;
+ }
+ return StringPiece(static_cast<const char*>(data), size);
+ }
+ }
+ return {};
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg) {
+ // TODO(gerbens) implement aliasing
+ auto next = [&input]() { return Next(&input); };
+ return ParseStream(next, msg) && input.limit == 0;
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg) {
+ // TODO(gerbens) implement aliasing
+ BoundedZCIS bounded_zcis{input, INT_MAX};
+ auto next = [&bounded_zcis]() { return Next(&bounded_zcis); };
+ return ParseStream(next, msg) && bounded_zcis.limit > 0;
+}
+
+
+#else
+
+inline bool InlineMergePartialEntireStream(io::CodedInputStream* cis,
+ MessageLite* message,
+ bool aliasing) {
+ return message->MergePartialFromCodedStream(cis) &&
+ cis->ConsumedEntireMessage();
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg) {
+ io::CodedInputStream decoder(reinterpret_cast<const uint8*>(input.data()),
+ input.size());
+ return InlineMergePartialEntireStream(&decoder, msg, aliasing);
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg) {
+ io::CodedInputStream decoder(input.zcis);
+ decoder.PushLimit(input.limit);
+ return InlineMergePartialEntireStream(&decoder, msg, aliasing) &&
+ decoder.BytesUntilLimit() == 0;
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg) {
+ io::CodedInputStream decoder(input);
+ return InlineMergePartialEntireStream(&decoder, msg, aliasing);
+}
+
+#endif
+
+template bool MergePartialFromImpl<false>(StringPiece input,
+ MessageLite* msg);
+template bool MergePartialFromImpl<true>(StringPiece input,
+ MessageLite* msg);
+template bool MergePartialFromImpl<false>(io::ZeroCopyInputStream* input,
+ MessageLite* msg);
+template bool MergePartialFromImpl<true>(io::ZeroCopyInputStream* input,
+ MessageLite* msg);
+template bool MergePartialFromImpl<false>(BoundedZCIS input, MessageLite* msg);
+template bool MergePartialFromImpl<true>(BoundedZCIS input, MessageLite* msg);
+
+} // namespace internal
+
MessageLite* MessageLite::New(Arena* arena) const {
MessageLite* message = New();
if (arena != NULL) {
@@ -485,100 +255,100 @@
}
#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* cis) {
- EpsCopyInputStream<internal::ParseContext::kSlopBytes> input(cis);
- internal::ParseContext ctx(cis->RecursionBudget());
- ctx.extra_parse_data().pool = cis->GetExtensionPool();
- ctx.extra_parse_data().factory = cis->GetExtensionFactory();
-
- auto chunk = input.SafeNextWithOverlap(
- [&ctx](const char* ptr, int n) { return ctx.EnsureNoEnd(ptr, n, 0); });
- if (chunk.empty()) {
- cis->SetConsumed();
- return true;
- }
- auto res = ctx.StartParse({_ParseFunc(), this}, chunk);
- while (res.first == internal::ParseContext::kContinue) {
- int overrun = res.second;
- chunk = input.SafeNextWithOverlap([&ctx, overrun](const char* ptr, int n) {
- return ctx.EnsureNoEnd(ptr, n, overrun);
- });
- if (chunk.empty()) {
- if (!ctx.ValidEnd(overrun)) goto error;
- cis->SetConsumed();
+bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
+ // MergePartialFromCodedStream must leave input in "exactly" the same state
+ // as the old implementation. At least when the parse is successful. For
+ // MergePartialFromCodedStream a successful parse can also occur by ending
+ // on a zero tag or an end-group tag. In these cases input is left precisely
+ // past the terminating tag and last_tag_ is set to the terminating tags
+ // value. If the parse ended on a limit (either a pushed limit or end of the
+ // ZeroCopyInputStream) legitimate_end_ is set to true.
+ int size = 0;
+ auto next = [input, &size]() {
+ const void* ptr;
+ input->Skip(size); // skip previous buffer
+ if (!input->GetDirectBufferPointer(&ptr, &size)) return StringPiece{};
+ return StringPiece(static_cast<const char*>(ptr), size);
+ };
+ internal::ParseContext ctx(input->RecursionBudget());
+ ctx.extra_parse_data().pool = input->GetExtensionPool();
+ ctx.extra_parse_data().factory = input->GetExtensionFactory();
+ internal::EpsCopyParser<true> parser({_ParseFunc(), this}, &ctx);
+ auto range = next();
+ while (!range.empty()) {
+ if (!parser.Parse(range)) {
+ if (!ctx.EndedOnTag()) return false;
+ // Parse ended on a zero or end-group tag, leave the stream in the
+ // appropriate state. Note we only skip forward, due to using
+ // ensure_non_negative_skip being set to true in parser.
+ input->Skip(parser.Skip());
+ input->SetLastTag(ctx.LastTag());
return true;
}
- res = ctx.ResumeParse(chunk, overrun);
+ range = next();
}
- // Either failure or ended on a zero or end-group tag
- if (res.first != internal::ParseContext::kFailure) {
- cis->SetLastTag(res.first);
- input.AdjustPos(res.second);
- return true;
- }
-error:
- // Error can happen at a spot from which we can't back up. But in this case
- // the user can't resume the stream as the error could be in an arbitrary
- // location in the stream, so just leave the stream alone. This prevents
- // triggering assertion fail.
- input.SetError();
- return false;
+ input->SetConsumed();
+ return parser.Done();
}
#endif
bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
- return InlineMergeFromCodedStream(input, this);
+ return MergePartialFromCodedStream(input) && IsInitializedWithErrors();
}
bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
- return InlineParseFromCodedStream(input, this);
+ Clear();
+ return MergeFromCodedStream(input);
}
bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
- return InlineParsePartialFromCodedStream(input, this);
+ Clear();
+ return MergePartialFromCodedStream(input);
}
bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
- io::CodedInputStream decoder(input);
- return InlineParseEntireStream(&decoder, this);
+ return ParseFrom<kParse>(input);
}
bool MessageLite::ParsePartialFromZeroCopyStream(
io::ZeroCopyInputStream* input) {
- io::CodedInputStream decoder(input);
- return InlineParsePartialEntireStream(&decoder, this);
+ return ParseFrom<kParsePartial>(input);
+}
+
+bool MessageLite::MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+ int size) {
+ return ParseFrom<kMergePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+ int size) {
+ return ParseFrom<kMerge>(internal::BoundedZCIS{input, size});
}
bool MessageLite::ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
int size) {
- io::CodedInputStream decoder(input);
- decoder.PushLimit(size);
- return InlineParseEntireStream(&decoder, this) &&
- decoder.BytesUntilLimit() == 0;
+ return ParseFrom<kParse>(internal::BoundedZCIS{input, size});
}
bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
io::ZeroCopyInputStream* input, int size) {
- io::CodedInputStream decoder(input);
- decoder.PushLimit(size);
- return InlineParsePartialEntireStream(&decoder, this) &&
- decoder.BytesUntilLimit() == 0;
+ return ParseFrom<kParsePartial>(internal::BoundedZCIS{input, size});
}
bool MessageLite::ParseFromString(const string& data) {
- return InlineParseFromArray(data.data(), data.size(), this);
+ return ParseFrom<kParse>(data);
}
bool MessageLite::ParsePartialFromString(const string& data) {
- return InlineParsePartialFromArray(data.data(), data.size(), this);
+ return ParseFrom<kParsePartial>(data);
}
bool MessageLite::ParseFromArray(const void* data, int size) {
- return InlineParseFromArray(data, size, this);
+ return ParseFrom<kParse>(as_string_view(data, size));
}
bool MessageLite::ParsePartialFromArray(const void* data, int size) {
- return InlineParsePartialFromArray(data, size, this);
+ return ParseFrom<kParsePartial>(as_string_view(data, size));
}
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 0e8c347..39c9e8f 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -46,6 +46,7 @@
#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>
@@ -259,6 +260,11 @@
// Read a protocol buffer from the given zero-copy input stream, expecting
// the message to be exactly "size" bytes long. If successful, exactly
// this many bytes will have been consumed from the input.
+ bool MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
+ // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+ // missing required fields.
+ bool MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+ int size);
bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
// Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
// missing required fields.
@@ -426,6 +432,21 @@
return Arena::CreateMaybeMessage<T>(arena);
}
+ public:
+ enum ParseFlags {
+ kMerge = 0,
+ kParse = 1,
+ kMergePartial = 2,
+ kParsePartial = 3,
+ kMergeWithAliasing = 4,
+ kParseWithAliasing = 5,
+ kMergePartialWithAliasing = 6,
+ kParsePartialWithAliasing = 7
+ };
+
+ template <ParseFlags flags, typename T>
+ bool ParseFrom(const T& input);
+
private:
// TODO(gerbens) make this a pure abstract function
virtual const void* InternalGetTable() const { return NULL; }
@@ -434,9 +455,64 @@
friend class Message;
friend class internal::WeakFieldMap;
+ bool IsInitializedWithErrors() const {
+ if (IsInitialized()) return true;
+ LogInitializationErrorMessage();
+ return false;
+ }
+
+ void LogInitializationErrorMessage() const;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
};
+namespace internal {
+
+template <bool alias>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(StringPiece input,
+ MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(StringPiece input,
+ MessageLite* msg);
+
+template <bool alias>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(io::ZeroCopyInputStream* input,
+ MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(io::ZeroCopyInputStream* input,
+ MessageLite* msg);
+
+struct BoundedZCIS {
+ io::ZeroCopyInputStream* zcis;
+ int limit;
+};
+
+template <bool alias>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(BoundedZCIS input,
+ MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(BoundedZCIS input,
+ MessageLite* msg);
+
+
+template <typename T>
+struct SourceWrapper;
+
+template <bool alias, typename T>
+bool MergePartialFromImpl(const SourceWrapper<T>& input, MessageLite* msg) {
+ return input.template MergePartialInto<alias>(msg);
+}
+
+} // namespace internal
+
+template <MessageLite::ParseFlags flags, typename T>
+bool MessageLite::ParseFrom(const T& input) {
+ if (flags & kParse) Clear();
+ constexpr bool alias = flags & kMergeWithAliasing;
+ return internal::MergePartialFromImpl<alias>(input, this) &&
+ ((flags & kMergePartial) || IsInitializedWithErrors());
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
new file mode 100644
index 0000000..3902637
--- /dev/null
+++ b/src/google/protobuf/parse_context.cc
@@ -0,0 +1,627 @@
+// 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.
+
+#include <google/protobuf/parse_context.h>
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/string_piece_field_support.h>
+#include <google/protobuf/wire_format_lite.h>
+#include "third_party/absl/strings/str_format.h"
+#include <google/protobuf/stubs/strutil.h>
+#include "util/coding/varint.h"
+#include "util/utf8/public/unilib.h"
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+bool ParseContext::ParseEndsInSlopRegion(const char* begin, int overrun) const {
+ ABSL_ASSERT(overrun >= 0);
+ ABSL_ASSERT(overrun <= kSlopBytes);
+ auto ptr = begin + overrun;
+ auto end = begin + kSlopBytes;
+ int n = end - ptr;
+ if (n == 0) return false;
+ // If limit_ != -1 then the parser will continue to parse at least limit_
+ // bytes (or more if on the stack there are further limits)
+ int d = depth_;
+ if (limit_ != -1) {
+ ABSL_ASSERT(d < start_depth_); // Top-level never has a limit.
+ // rewind the stack until all limits disappear.
+ int limit = limit_;
+ if (limit >= n) return false;
+ while (d < start_depth_) {
+ int delta = stack_[d++].delta_or_group_num;
+ if (delta == -1) {
+ // We found the first limit that was pushed. We should inspect from
+ // this point on.
+ ptr += limit;
+ break;
+ } else if (delta >= 0) {
+ // We reached end of a length delimited subfield. Adjust limit
+ limit += delta;
+ if (limit >= n) return false;
+ } else {
+ // It's a group we assume the format is correct and this group
+ // is properly ended before the limit is reached.
+ }
+ }
+ }
+ d = start_depth_ - d; // We just keep track of the depth from start.
+ // We verify that a generic parse of the buffer won't, validly, end the parse
+ // before end, due to ending the top-level on a 0 or end-group tag.
+ // IMPORTANT NOTE: we return false in failure cases. This is
+ // important because we could fail due to overrunning the buffer and read
+ // garbage data beyond the buffer (valid reads just left over garbage). So
+ // failure doesn't imply the parse will fail. So if this loops fails while
+ // the real parse would succeed it means the real parse will read beyond the
+ // boundary. If the real parse fails we can't reasonably continue the stream
+ // any way so we make no attempt to leave the stream at a well specified pos.
+ while (ptr < end) {
+ uint32 tag;
+ ptr = Varint::Parse32(ptr, &tag);
+ if (ptr == nullptr || ptr > end) return false;
+ // ending on 0 tag is allowed and is the major reason for the necessity of
+ // this function.
+ if (tag == 0) return true;
+ switch (tag & 7) {
+ case 0: { // Varint
+ uint64 val;
+ ptr = Varint::Parse64(ptr, &val);
+ if (ptr == nullptr) return false;
+ break;
+ }
+ case 1: { // fixed64
+ ptr += 8;
+ break;
+ }
+ case 2: { // len delim
+ uint32 size;
+ ptr = Varint::Parse32(ptr, &size);
+ if (ptr == nullptr) return false;
+ ptr += size;
+ break;
+ }
+ case 3: { // start group
+ d++;
+ break;
+ }
+ case 4: { // end group
+ if (--d < 0) return true; // We exit early
+ break;
+ }
+ case 5: { // fixed32
+ ptr += 4;
+ break;
+ }
+ default:
+ return false; // Unknown wireformat
+ }
+ }
+ return false;
+}
+
+void ParseContext::SwitchStack() {
+ stack_ = new State[start_depth_];
+ std::memcpy(stack_ + inlined_depth_, inline_stack_, sizeof(inline_stack_));
+ inlined_depth_ = -1; // Special value to indicate stack_ needs to be deleted
+}
+
+std::pair<bool, int> ParseContext::ParseRangeWithLimit(const char* begin,
+ const char* end) {
+ auto ptr = begin;
+ do {
+ ABSL_ASSERT(ptr < end);
+ const char* limited_end;
+ if (limit_ == -1) {
+ limited_end = end;
+ } else {
+ ABSL_ASSERT(limit_ > 0);
+ limited_end = ptr + std::min(static_cast<int32>(end - ptr), limit_);
+ limit_ -= limited_end - ptr;
+ }
+ // Parse the range [ptr, limited_end). The only case (except for error) that
+ // the parser can return prematurely (before limited_end) is on encountering
+ // an end-group. If this is the case we continue parsing the range with
+ // the parent parser.
+ do {
+ ABSL_ASSERT(ptr < limited_end);
+ ptr = parser_(ptr, limited_end, this);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ // Clear last_tag_minus_1_ so that the hard error encountered is not
+ // mistaken for ending on a tag.
+ last_tag_minus_1_ = 0;
+ return {};
+ }
+ if (!EndedOnTag()) {
+ // The parser ended still parsing the initial message. This can only
+ // happen because it crossed the end.
+ ABSL_ASSERT(ptr >= limited_end);
+ break;
+ }
+ // Child parser terminated on an end-group / 0 tag.
+ ABSL_ASSERT(depth_ <= start_depth_);
+ if (depth_ == start_depth_) {
+ // The parse was already at the top-level and there is no parent.
+ // This can happen due to encountering 0 or due to this parser being
+ // called for parsing a sub-group message in custom parsing code.
+ return {false, ptr - end};
+ }
+ auto state = Pop();
+ // Verify the ending tag is correct and continue parsing the range with
+ // the parent parser.
+ uint32 group_number = last_tag_minus_1_ >> 3;
+ // We need to clear last_tag_minus_1_, either for the next iteration
+ // or if the if statement below returns.
+ last_tag_minus_1_ = 0;
+ if (state.delta_or_group_num != ~group_number) return {};
+ parser_ = state.parser; // Load parent parser
+ } while (ptr < limited_end);
+ int overrun = ptr - limited_end;
+ ABSL_ASSERT(overrun >= 0);
+ ABSL_ASSERT(overrun <= kSlopBytes); // wireformat guarantees this limit
+ if (limit_ != -1) {
+ limit_ -= overrun; // Adjust limit relative to new position.
+ if (limit_ < 0) return {}; // We overrun the limit
+ while (limit_ == 0) {
+ // We are at an actual ending of a length delimited field.
+ // The top level has no limit (ie. limit_ == -1) so we can assert
+ // that the stack is non-empty.
+ ABSL_ASSERT(depth_ < start_depth_);
+ // else continue parsing the parent message.
+ auto state = Pop();
+ parser_ = state.parser;
+ limit_ = state.delta_or_group_num;
+ // No group ending is possible here. Any group on the stack still
+ // needs to read its end-group tag and can't be on a limit_ == 0.
+ if (limit_ < -1) return {};
+ }
+ }
+ } while (ptr < end);
+ return {true, ptr - end};
+}
+
+const char* StringParser(const char* begin, const char* end, void* object,
+ ParseContext*) {
+ auto str = static_cast<string*>(object);
+ str->append(begin, end - begin);
+ return end;
+}
+
+const char* CordParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto cord = static_cast<Cord*>(object);
+ cord->Append(StringPiece(begin, end - begin));
+ return end;
+}
+
+void StringPieceField::Append(const char *begin, size_t chunk_size, int limit) {
+ if (size_ == 0) {
+ auto tot = chunk_size + limit;
+ if (tot > scratch_size_) {
+ auto old_scratch_size = scratch_size_;
+ scratch_size_ = tot;
+ // TODO(gerbens) Security against big
+ if (arena_ != NULL) {
+ scratch_ = ::google::protobuf::Arena::CreateArray<char>(arena_, scratch_size_);
+ } else {
+ std::allocator<char>().deallocate(scratch_, old_scratch_size);
+ scratch_ = std::allocator<char>().allocate(scratch_size_);
+ }
+ }
+ data_ = scratch_;
+ }
+ std::memcpy(scratch_ + size_, begin, chunk_size);
+ size_ += chunk_size;
+}
+
+const char* StringPieceParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto s = static_cast<StringPieceField*>(object);
+ auto limit = ctx->CurrentLimit();
+ s->Append(begin, end - begin, limit);
+ return end;
+}
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
+ bool emit_stacktrace);
+
+bool VerifyUTF8(StringPiece str, ParseContext* ctx) {
+ if (!IsStructurallyValidUTF8(str)) {
+ PrintUTF8ErrorLog(ctx->extra_parse_data().FieldName(), "parsing", false);
+ return false;
+ }
+ return true;
+}
+
+bool VerifyUTF8Cord(const Cord& value, ParseContext* ctx) {
+ if (!UniLib::CordIsStructurallyValid(value)) {
+ PrintUTF8ErrorLog(ctx->extra_parse_data().FieldName(), "parsing", false);
+ return false;
+ }
+ return true;
+}
+
+const char* StringParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ StringParser(begin, end, object, ctx);
+ if (ctx->AtLimit()) {
+ auto str = static_cast<string*>(object);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
+ }
+ return end;
+}
+
+const char* CordParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ CordParser(begin, end, object, ctx);
+ if (ctx->AtLimit()) {
+ auto str = static_cast<Cord*>(object);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8Cord(*str, ctx));
+ }
+ return end;
+}
+
+const char* StringPieceParserUTF8(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ StringPieceParser(begin, end, object, ctx);
+ if (ctx->AtLimit()) {
+ auto s = static_cast<StringPieceField*>(object);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(s->Get(), ctx));
+ }
+ return end;
+}
+
+const char* StringParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ StringParser(begin, end, object, ctx);
+#ifndef NDEBUG
+ if (ctx->AtLimit()) {
+ auto str = static_cast<string*>(object);
+ VerifyUTF8(*str, ctx);
+ }
+#endif
+ return end;
+}
+
+const char* CordParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ CordParser(begin, end, object, ctx);
+#ifndef NDEBUG
+ if (ctx->AtLimit()) {
+ auto str = static_cast<Cord*>(object);
+ VerifyUTF8Cord(*str, ctx);
+ }
+#endif
+ return end;
+}
+
+const char* StringPieceParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ return StringPieceParser(begin, end, object, ctx);
+#ifndef NDEBUG
+ if (ctx->AtLimit()) {
+ auto s = static_cast<StringPieceField*>(object);
+ VerifyUTF8(s->Get(), ctx);
+ }
+#endif
+ return end;
+}
+
+const char* GreedyStringParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto str = static_cast<string*>(object);
+ auto limit = ctx->CurrentLimit();
+ ABSL_ASSERT(limit != -1); // Always length delimited
+ end += std::min<int>(limit, ParseContext::kSlopBytes);
+ str->append(begin, end - begin);
+ return end;
+}
+
+const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto limit = ctx->CurrentLimit();
+ ABSL_ASSERT(limit != -1); // Always length delimited
+ bool at_end;
+ if (limit <= ParseContext::kSlopBytes) {
+ end += limit;
+ at_end = true;
+ } else {
+ end += ParseContext::kSlopBytes;
+ at_end =false;
+ }
+ auto str = static_cast<string*>(object);
+ str->append(begin, end - begin);
+ if (at_end) {
+ GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
+ }
+ return end;
+}
+
+const char* GreedyStringParserUTF8Verify(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto limit = ctx->CurrentLimit();
+ ABSL_ASSERT(limit != -1); // Always length delimited
+ bool at_end;
+ if (limit <= ParseContext::kSlopBytes) {
+ end += limit;
+ at_end = true;
+ } else {
+ end += ParseContext::kSlopBytes;
+ at_end =false;
+ }
+ auto str = static_cast<string*>(object);
+ str->append(begin, end - begin);
+ if (at_end) {
+#ifndef NDEBUG
+ VerifyUTF8(*str, ctx);
+#endif
+ }
+ return end;
+}
+
+template <typename T, bool sign>
+const char* VarintParser(const char* begin, const char* end, void* object,
+ ParseContext*) {
+ auto repeated_field = static_cast<RepeatedField<T>*>(object);
+ auto ptr = begin;
+ while (ptr < end) {
+ uint64 varint;
+ ptr = Varint::Parse64(ptr, &varint);
+ if (!ptr) return nullptr;
+ T val;
+ if (sign) {
+ if (sizeof(T) == 8) {
+ val = WireFormatLite::ZigZagDecode64(varint);
+ } else {
+ val = WireFormatLite::ZigZagDecode32(varint);
+ }
+ } else {
+ val = varint;
+ }
+ repeated_field->Add(val);
+ }
+ return ptr;
+}
+
+template <typename T>
+const char* FixedParser(const char* begin, const char* end, void* object,
+ ParseContext*) {
+ auto repeated_field = static_cast<RepeatedField<T>*>(object);
+ int num = (end - begin + sizeof(T) - 1) / sizeof(T);
+
+ const int old_entries = repeated_field->size();
+ repeated_field->Reserve(old_entries + num);
+ std::memcpy(repeated_field->AddNAlreadyReserved(num), begin, num * sizeof(T));
+ return begin + num * sizeof(T);
+}
+
+const char* PackedInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<int32, false>(begin, end, object, ctx);
+}
+const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<uint32, false>(begin, end, object, ctx);
+}
+const char* PackedInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<int64, false>(begin, end, object, ctx);
+}
+const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<uint64, false>(begin, end, object, ctx);
+}
+const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<int32, true>(begin, end, object, ctx);
+}
+const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<int64, true>(begin, end, object, ctx);
+}
+
+const char* PackedEnumParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<int, false>(begin, end, object, ctx);
+}
+
+const char* PackedValidEnumParserLite(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ auto repeated_field = static_cast<RepeatedField<int>*>(object);
+ auto ptr = begin;
+ while (ptr < end) {
+ uint64 varint;
+ ptr = Varint::Parse64(ptr, &varint);
+ if (!ptr) return nullptr;
+ int val = varint;
+ if (ctx->extra_parse_data().ValidateEnum<string>(val))
+ repeated_field->Add(val);
+ }
+ return ptr;
+}
+
+const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ auto repeated_field = static_cast<RepeatedField<int>*>(object);
+ auto ptr = begin;
+ while (ptr < end) {
+ uint64 varint;
+ ptr = Varint::Parse64(ptr, &varint);
+ if (!ptr) return nullptr;
+ int val = varint;
+ if (ctx->extra_parse_data().ValidateEnumArg<string>(val))
+ repeated_field->Add(val);
+ }
+ return ptr;
+}
+
+const char* PackedBoolParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return VarintParser<bool, false>(begin, end, object, ctx);
+}
+
+const char* PackedFixed32Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ return FixedParser<uint32>(begin, end, object, ctx);
+}
+const char* PackedSFixed32Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ return FixedParser<int32>(begin, end, object, ctx);
+}
+const char* PackedFixed64Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ return FixedParser<uint64>(begin, end, object, ctx);
+}
+const char* PackedSFixed64Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ return FixedParser<int64>(begin, end, object, ctx);
+}
+const char* PackedFloatParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return FixedParser<float>(begin, end, object, ctx);
+}
+const char* PackedDoubleParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return FixedParser<double>(begin, end, object, ctx);
+}
+
+const char* NullParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ return end;
+}
+
+void WriteVarint(uint64 val, string* s) {
+ while (val >= 128) {
+ uint8 c = val | 0x80;
+ s->push_back(c);
+ val >>= 7;
+ }
+ s->push_back(val);
+}
+
+void WriteVarint(uint32 num, uint64 val, string* s) {
+ WriteVarint(num << 3, s);
+ WriteVarint(val, s);
+}
+
+void WriteLengthDelimited(uint32 num, StringPiece val, string* s) {
+ WriteVarint((num << 3) + 2, s);
+ WriteVarint(val.size(), s);
+ s->append(val.data(), val.size());
+}
+
+class UnknownFieldLiteParserHelper {
+ public:
+ explicit UnknownFieldLiteParserHelper(string* unknown) : unknown_(unknown) {}
+
+ void AddVarint(uint32 num, uint64 value) {
+ if (unknown_ == nullptr) return;
+ WriteVarint(num * 8, unknown_);
+ WriteVarint(value, unknown_);
+ }
+ void AddFixed64(uint32 num, uint64 value) {
+ if (unknown_ == nullptr) return;
+ WriteVarint(num * 8 + 1, unknown_);
+ char buffer[8];
+ std::memcpy(buffer, &value, 8);
+ unknown_->append(buffer, 8);
+ }
+ ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
+ if (unknown_ == nullptr) return {NullParser, nullptr};
+ WriteVarint(num * 8 + 2, unknown_);
+ WriteVarint(size, unknown_);
+ return {StringParser, unknown_};
+ }
+ ParseClosure StartGroup(uint32 num) {
+ if (unknown_ == nullptr) return {UnknownGroupLiteParse, nullptr};
+ WriteVarint(num * 8 + 3, unknown_);
+ return {UnknownGroupLiteParse, unknown_};
+ }
+ void EndGroup(uint32 num) {
+ if (unknown_ == nullptr) return;
+ WriteVarint(num * 8 + 4, unknown_);
+ }
+ void AddFixed32(uint32 num, uint32 value) {
+ if (unknown_ == nullptr) return;
+ WriteVarint(num * 8 + 5, unknown_);
+ char buffer[4];
+ std::memcpy(buffer, &value, 4);
+ unknown_->append(buffer, 4);
+ }
+
+ private:
+ string* unknown_;
+};
+
+const char* UnknownGroupLiteParse(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ UnknownFieldLiteParserHelper field_parser(static_cast<string*>(object));
+ return WireFormatParser({UnknownGroupLiteParse, object}, field_parser, begin,
+ end, ctx);
+}
+
+std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
+ const char* begin,
+ const char* end, string* unknown,
+ ParseContext* ctx) {
+ UnknownFieldLiteParserHelper field_parser(unknown);
+ return FieldParser(tag, parent, field_parser, begin, end, ctx);
+}
+
+const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
+ internal::ParseContext* ctx) {
+ ctx->extra_parse_data().payload.append(begin, end - begin);
+ if (ctx->AtLimit()) {
+ // Move payload out of extra_parse_data. Parsing maps could trigger
+ // payload on recursive maps.
+ string to_parse = std::move(ctx->extra_parse_data().payload);
+ StringPiece chunk = to_parse;
+ if (!ctx->extra_parse_data().parse_map(chunk.begin(), chunk.end(), object,
+ ctx)) {
+ return nullptr;
+ }
+ }
+ return end;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
new file mode 100644
index 0000000..c7d37db
--- /dev/null
+++ b/src/google/protobuf/parse_context.h
@@ -0,0 +1,821 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+#define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+
+#include <string>
+
+#include <google/protobuf/port.h>
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/common.h>
+#include "third_party/absl/base/optimization.h"
+#include <google/protobuf/stubs/strutil.h>
+#include "util/coding/varint.h"
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class UnknownFieldSet;
+class DescriptorPool;
+class MessageFactory;
+
+namespace internal {
+
+// Template code below needs to know about the existence of these functions.
+void WriteVarint(uint32 num, uint64 val, std::string* s);
+void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s);
+// Inline because it is just forwarding to s->WriteVarint
+inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* s);
+inline void WriteLengthDelimited(uint32 num, StringPiece val,
+ UnknownFieldSet* s);
+
+
+// ParseContext contains state that needs to be preserved across buffer seams.
+
+class ParseContext;
+
+// The parser works by composing elementary parse functions, that are generated
+// by the compiler, together to perform the full parse. To accomplish this the
+// functionality of the elementary parse function is slightly increased which
+// allows it to become composable.
+
+// The basic abstraction ParseContext is designed for is a slight modification
+// of the ZeroCopyInputStream (ZCIS) abstraction. A ZCIS presents a serialized
+// stream as a series of buffers that concatenate to the full stream.
+// Pictorially a ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+// [----------------------------] chunk 2
+// chunk 3 [--------------]
+//
+// Where the '-' represent the bytes which are vertically lined up with the
+// bytes of the stream.
+// ParseContext requires its input to be presented similarily with the extra
+// property that the last kSlopBytes of a chunk overlaps with the first
+// kSlopBytes of the next chunk, or if there is no next chunk at least its still
+// valid to read those bytes. Again, pictorially, we now have
+//
+// [---------------------------------------------------------------]
+// [-------------------....] chunk 1
+// [------------------------....] chunk 2
+// chunk 3 [------------------..**]
+// chunk 4 [--****]
+// Here '-' mean the bytes of the stream or chunk and '.' means bytes past the
+// chunk that match up with the start of the next chunk. Above each chunk has
+// 4 '.' after the chunk. In the case these 'overflow' bytes represents bytes
+// past the stream, indicated by '*' above, their values are unspecified. It is
+// still legal to read them (ie. should not segfault). Reading past the
+// end should be detected by the user and indicated as an error.
+//
+// The reason for this, admittedly, unconventional invariant is to ruthlessly
+// optimize the protobuf parser. Having an overlap helps in two important ways.
+// Firstly it alleviates having to performing bounds checks, if a piece of code
+// will never read more than kSlopBytes. Secondly, and more importantly, the
+// protobuf wireformat is such that there is always a fresh start of a tag
+// within kSlopBytes. This allows the parser to exit parsing a chunk leaving
+// the parse on a position inside the overlap where a fresh tag starts.
+
+// The elementary parse function has the following signature
+
+typedef const char* (*ParseFunc)(const char* ptr, const char* end, void* object,
+ ParseContext* ctx);
+
+// which parses the serialized data stored in the range [ptr, end) into object.
+// A parse function together with its object forms a callable closure.
+struct ParseClosure {
+ ParseFunc func;
+ void* object;
+
+ // Pre-conditions
+ // ptr < end is a non-empty range where ptr points to the start of a tag
+ // and it's okay to read the bytes in [end, end + kSlopBytes).
+ // Which will contain the bytes of the next chunk if the stream continues,
+ // or undefined in which case the parse will be guaranteed to fail.
+ //
+ // Post-conditions
+ // Parsed all tag/value pairs starting before end or if a group end
+ // tag is encountered returns the pointer to that tag.
+ // If a group end is encountered it verifies it matches the one that was
+ // pushed and the stack is popped.
+ // Otherwise it will parses the entire range pushing if end is inside one
+ // of the children those are pushed on the stack.
+ //
+ // If an element is popped from the stack it ended on the correct end group
+ // returns pointer after end-group tag (posibly in overlap, but the start
+ // of end-group tag will be before end).
+ // If the stack is the same or deeper, returns pointer in overlap region
+ // (end <= retval < end + kSlopBytes).
+ // All tag/value pairs between in [begin, retval) are parsed and retval
+ // points to start of a tag.
+ const char* operator()(const char* ptr, const char* end, ParseContext* ctx) {
+ ABSL_ASSERT(ptr < end);
+ return func(ptr, end, object, ctx);
+ }
+};
+
+// To fully parse a stream, a driver loop repeatedly calls the parse function
+// at the top of the stack, popping and resume parsing the parent message
+// according to the recursive structure of the wireformat. This loop will also
+// need to provide new buffer chunks and align the ptr correctly over the seams.
+// The point of this framework is that chunk refresh logic is located in the
+// outer loop, while the inner loop is almost free of it. The two code paths in
+// the parse code dealing with seams are located in fallback paths whose checks
+// are folded with input limit checks that are necessary anyway. In other words,
+// all the parser code that deals with seams is located in what would otherwise
+// be error paths of a parser that wouldn't need to deal with seams.
+
+class ParseContext {
+ public:
+ enum {
+ // Tag is atmost 5 bytes, varint is atmost 10 resulting in 15 bytes. We
+ // choose
+ // 16 bytes for the obvious reason of alignment.
+ kSlopBytes = 16,
+ // Inlined stack size
+ kInlinedDepth = 15,
+ };
+
+ // Arghh!!! here be tech-debt dragons
+ struct ExtraParseData {
+ const DescriptorPool* pool = nullptr;
+ MessageFactory* factory = nullptr;
+
+ // payload is used for MessageSetItem and maps
+ std::string payload;
+ bool (*parse_map)(const char* begin, const char* end, void* map_field,
+ ParseContext* ctx);
+
+ void SetEnumValidator(bool (*validator)(int), void* unknown,
+ int field_num) {
+ enum_validator = validator;
+ unknown_fields = unknown;
+ field_number = field_num;
+ }
+ void SetEnumValidatorArg(bool (*validator)(const void*, int),
+ const void* arg, void* unknown, int field_num) {
+ arg_enum_validator = {validator, arg};
+ unknown_fields = unknown;
+ field_number = field_num;
+ }
+ template <typename Unknown>
+ bool ValidateEnum(int val) const {
+ if (enum_validator(val)) return true;
+ WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
+ return false;
+ }
+ template <typename Unknown>
+ bool ValidateEnumArg(int val) const {
+ if (arg_enum_validator(val)) return true;
+ WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
+ return false;
+ }
+
+ void SetFieldName(const void* name) {
+ unknown_fields = const_cast<void*>(name);
+ }
+ const char* FieldName() const {
+ return static_cast<const char*>(unknown_fields);
+ }
+
+ union {
+ bool (*enum_validator)(int);
+ struct {
+ bool operator()(int val) const { return validator(arg, val); }
+ bool (*validator)(const void*, int);
+ const void* arg;
+ } arg_enum_validator;
+ };
+ void* unknown_fields;
+ int field_number;
+ // 0 means no aliasing. If not zero aliasing is the delta between the
+ // ptr and the buffer that needs to be aliased. If the value is
+ // kNoDelta (1) this means delta is actually 0 (we're working directly in
+ // the buffer).
+ enum { kNoDelta = 1 };
+ std::uintptr_t aliasing = 0;
+ };
+
+ ExtraParseData& extra_parse_data() { return extra_parse_data_; }
+ const ExtraParseData& extra_parse_data() const { return extra_parse_data_; }
+
+ // Helpers to detect if a parse of length delimited field is completed.
+ bool AtLimit() const { return limit_ == 0; }
+ int32 CurrentLimit() const { return limit_; }
+
+ // Initializes ParseContext with a specific recursion limit (rec_limit)
+ explicit ParseContext(int rec_limit)
+ : depth_(rec_limit),
+ start_depth_(rec_limit),
+ stack_(inline_stack_ + kInlinedDepth - rec_limit),
+ inlined_depth_(std::max(0, rec_limit - kInlinedDepth)) {}
+
+ ~ParseContext() {
+ if (inlined_depth_ == -1) delete stack_;
+ }
+
+ void StartParse(ParseClosure parser) { parser_ = parser; }
+
+ // Parses a chunk of memory given the current state of parse context (ie.
+ // the active parser and stack) and overrun.
+ // Pre-condition:
+ // chunk_ is not empty.
+ // limit_ > 0 (limit from begin) or -1 (no limit)
+ // Post-condition:
+ // returns true on success with overrun_ptr adjusted to the new value, or
+ // false is the parse is finished. False means either a parse failure or
+ // or because the top-level was terminated on a 0 or end-group tag in which
+ // case overrun points to the position after the ending tag. You can call
+ // EndedOnTag() to find if the parse failed due to an error or ended on
+ // terminating tag.
+ bool ParseRange(StringPiece chunk, int* overrun_ptr) {
+ ABSL_ASSERT(!chunk.empty());
+ int& overrun = *overrun_ptr;
+ if (overrun >= chunk.size()) {
+ // This case can easily happen in patch buffers and we like to inline
+ // this case.
+ overrun -= chunk.size();
+ return true;
+ }
+ auto res = ParseRangeWithLimit(chunk.begin() + overrun, chunk.end());
+ overrun = res.second;
+ return res.first;
+ }
+
+ bool ValidEnd(int overrun) { return depth_ == start_depth_ && overrun == 0; }
+ bool EndedOnTag() const { return last_tag_minus_1_ != 0; }
+ uint32 LastTag() const { return last_tag_minus_1_ + 1; }
+
+ // Generically verifies for the slop region [begin, begin + kSlopBytes) if
+ // the parse will be terminated by 0 or end-group tag. If true than you can
+ // safely parse the slop region without having to load more data.
+ bool ParseEndsInSlopRegion(const char* begin, int overrun) const;
+
+ // Should only be called by Parse code.
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Fast path helpers. These helpers maintain the state in parse context
+ // through recursive calls. The whole design is to make this as minimal as
+ // possible. Only recursion depth and limit are maintained at every recursion.
+ //////////////////////////////////////////////////////////////////////////////
+
+ bool ParseExactRange(ParseClosure parser, const char* begin,
+ const char* end) {
+ if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
+ auto old_limit = limit_;
+ limit_ = 0;
+ auto ptr = begin;
+ if (ptr < end) ptr = parser(ptr, end, this);
+ if (ptr != end || EndedOnTag()) return false;
+ limit_ = old_limit;
+ ++depth_;
+ return true;
+ }
+
+ // Returns a pair of the pointer the parse is left and a boolean indicating
+ // if the group is still continuing.
+ std::pair<const char*, bool> ParseGroup(uint32 tag, ParseClosure parser,
+ const char* begin, const char* end,
+ int* depth) {
+ if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return {};
+ *depth = depth_;
+ auto ptr = begin;
+ if (ptr < end) ptr = parser(ptr, end, this);
+ if (ptr == nullptr) return {};
+ if (!EndedOnTag()) {
+ // The group hasn't been terminated by an end-group and thus continues,
+ // hence it must have ended because it crossed "end".
+ ABSL_ASSERT(ptr >= end);
+ return {ptr, true};
+ }
+ // Verify that the terminating tag matches the start group tag. As an extra
+ // subtlety it could have been terminated by an end-group tag but in a
+ // length delimited sub field of the group. So we must also check that depth
+ // matches, if it doesn't match it means a length delimited subfield got
+ // terminated by an end group which is an error.
+ if (tag != last_tag_minus_1_ || *depth != depth_) return {};
+ last_tag_minus_1_ = 0; // It must always be cleared.
+ ++depth_;
+ return {ptr, false};
+ }
+
+ void EndGroup(uint32 tag) {
+ ABSL_ASSERT(tag == 0 || (tag & 7) == 4);
+ // Because of the above assert last_tag_minus_1 is never set to 0, and the
+ // caller can verify the child parser was terminated, by comparing to 0.
+ last_tag_minus_1_ = tag - 1;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Slow path helper functions when a child crosses the "end" of range.
+ // This is either an error (if limit_ = 0) OR we need to store state.
+ // These functions manage the task of updating the state correctly.
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Helper function called by generated code in case of a length delimited
+ // field that is going to cross the boundary.
+ const char* StoreAndTailCall(const char* ptr, const char* end,
+ ParseClosure current_parser,
+ ParseClosure child_parser, int32 size) {
+ // if size was bigger than 2GB we should fail
+ if (size < 0) return nullptr;
+ // At this point ptr could be past end. Hence a malicious size could
+ // overflow.
+ int64 safe_new_limit = size - static_cast<int64>(end - ptr);
+ if (safe_new_limit > INT_MAX) return nullptr;
+ ABSL_ASSERT(safe_new_limit > 0); // only call this if it's crossing end
+ int32 new_limit = static_cast<int32>(safe_new_limit);
+ int32 delta;
+ if (limit_ != -1) {
+ if (PROTOBUF_PREDICT_FALSE(new_limit > limit_)) return nullptr;
+ delta = limit_ - new_limit;
+ } else {
+ delta = -1; // special value
+ }
+ limit_ = new_limit;
+ // Save the current closure on the stack.
+ if (!Push(current_parser, delta)) return nullptr;
+ // Ensure the active state is set correctly.
+ parser_ = child_parser;
+ return ptr < end ? child_parser(ptr, end, this) : ptr;
+ }
+
+ // Helper function for a child group that has crossed the boundary.
+ bool StoreGroup(ParseClosure current_parser, ParseClosure child_parser,
+ int depth, uint32 tag) {
+ // The group must still read an end-group tag, so it can't be at a limit.
+ // By having this check we ensure that when limit_ = 0 we can't end in some
+ // deeper recursion. Hence ParseExactRange does not need to check for
+ // matching depth.
+ if (limit_ == 0) return false;
+ if (depth == depth_) {
+ // This child group is the active parser. The fast path code assumes
+ // everything will be parsed within a chunk and doesn't modify
+ // parse context in this case. We need to make the child parser active.
+ parser_ = child_parser;
+ }
+ if (ABSL_PREDICT_FALSE(depth < inlined_depth_)) SwitchStack();
+ stack_[depth] = {current_parser, static_cast<int32>(~(tag >> 3))};
+ return true;
+ }
+
+ private:
+ // This the "active" or current parser.
+ ParseClosure parser_;
+ // The context keeps an internal stack to keep track of the recursive
+ // part of the parse state.
+ // Current depth of the active parser, depth counts down.
+ // This is used to limit recursion depth (to prevent overflow on malicious
+ // data), but is also used to index in stack_ to store the current state.
+ int depth_;
+ int32 limit_ = -1;
+
+ // A state is on the stack to save it, in order to continue parsing after
+ // child is done.
+ struct State {
+ ParseClosure parser;
+ // This element describes how to adjust the parse state after finishing
+ // the child. If the child was a length delimited field, delta describes
+ // the limit relative to the child's limit (hence >= 0).
+ // If child was a sub group limit contains ~field num (hence < 0) in order
+ // to verify the group ended on a correct end tag. No limit adjusting.
+ // Note above the sign of delta is meaningful
+ int32 delta_or_group_num;
+ };
+ int start_depth_;
+ // This is used to return the end group (or 0 tag) that terminated the parse.
+ // Actually it contains last_tag minus 1. Which is either the start group tag
+ // or -1. This member should always be zero and the caller should immediately
+ // check this member to verify what state the parser ended on and clear its
+ // value.
+ uint32 last_tag_minus_1_ = 0;
+
+ ExtraParseData extra_parse_data_;
+ State* stack_;
+ State inline_stack_[kInlinedDepth];
+ int inlined_depth_;
+
+ bool Push(ParseClosure parser, int32 delta) {
+ ABSL_ASSERT(delta >= -1); // Make sure it's a valid len-delim
+ if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
+ if (ABSL_PREDICT_FALSE(depth_ < inlined_depth_)) SwitchStack();
+ stack_[depth_] = {parser, delta};
+ return true;
+ }
+
+ State Pop() { return stack_[depth_++]; }
+
+ void SwitchStack();
+
+ // Parses a chunk of memory given the current state of parse context (ie.
+ // the active parser and stack).
+ // Pre-condition:
+ // begin < end (non-empty range)
+ // limit_ > 0 (limit from begin) or -1 (no limit)
+ // Post-condition:
+ // returns either (true, overrun) for a successful parse that can continue,
+ // or (false, overrun) for a parse that can't continue. Either due to a
+ // corrupt data (parse failure) or because the top-level was terminated on a
+ // 0 or end-group tag in which case overrun points to the position after the
+ // end.
+ std::pair<bool, int> ParseRangeWithLimit(const char* begin, const char* end);
+};
+
+// This is wrapper to parse a sequence of buffers without the overlap property,
+// like the sequence given by ZeroCopyInputStream (ZCIS) or ByteSource. This is
+// done by copying data around the seams, hence the name EpsCopyParser.
+// Pictorially if ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+// [----------------------------] chunk 2
+// chunk 3 [--------------]
+// where '-' depicts bytes of the stream or chunks vertically alligned with the
+// corresponding bytes between stream and chunk.
+//
+// This class will present chunks to the ParseContext like this
+// [-----------------....] chunk 1
+// [----....] patch
+// [------------------------....] chunk 2
+// [----....] patch
+// chunk 3 [----------....]
+// patch [----****]
+// by using a fixed size buffer to patch over the seams. This requires
+// copying of an "epsilon" neighboorhood around the seams. In the picture above
+// dots mean bytes beyond the end of the new chunks. Each chunk is kSlopBytes
+// smalller as its original chunk (above depicted as 4 dots) and the number of
+// of chunks is doubled because each seam in the original stream introduces a
+// new patch.
+//
+// The algorithm is simple but not entirely trivial. Two complications arise
+// 1) The original chunk could be less than kSlopBytes. Hence we can't simply
+// chop the last kSlopBytes of a chunk.
+// 2) In some (infrequent) use cases, we don't necessarily parse unitl the end
+// of a stream, but instead the parse is terminated by 0 or end-group tag. If
+// this is allowed we must take care to leave the underlying stream at a
+// position precisely after the terminating tag. If this happens in the slop
+// region of a buffer we will already have loaded the next buffer. Not all
+// streams allow backing up to a previous buffer blocking us from leaving the
+// stream in the proper state. If terminating on 0 is allowed (in the old parser
+// this means a call to MergePartialFromCodedStream without a subsequent call to
+// ConsumedEntireMessage), this algorithm needs to ensure the parse won't end
+// in the slop region before moving the next buffer.
+//
+// The core idea of EpsCopyParser is to parse ranges except the last kSlopBytes
+// and store those in the patch buffer, until the next parse provides additional
+// data to fill the slop region. So parsing a range means first parsing the slop
+// bytes of the previous range using the new range to provide slop bytes for the
+// patch, followed by parsing the actual range except the last kSlopBytes and
+// store those. If no more data is available a call to Done finishes the parse
+// by parsing the remaining slopbytes.
+//
+// In order to deal with problem 1, we need to deal with the case that a new
+// chunk can be less or equal than kSlopBytes big. We can just copy the chunk
+// to the end and return (buffer, chunk->size). Pictorially
+// [--------] chunk 1
+// [--] chunk 2
+// [---] chunk 3
+// will become
+// [----....] chunk 1
+// [--....] patch (not full range of the patch buffer, only two hyphens)
+// [--] chunk 2 (too small so never parsed directly)
+// [---....] patch (not full range of the buffer, only three hyphens)
+// [---] chunk 3 (too small so never parsed directly)
+// [----****] patch (full range, last bytes are garbage)
+// Because of this the source (the dots in above) can overlap with the
+// destination buffer and so we have to use memmove.
+//
+// To solve problem 2, we use a generic parser together with knowledge of the
+// nesting from the side stack to verify if the parse will be terminated in the
+// slop region. If it terminates inside the slop region, we just parse it as
+// well. See ParseEndsInSlopRegion in ParseContext for the implementation. This
+// is only done if ensure_non_negative_skip is true, if it's false Skip() could
+// return a negative number.
+template <bool ensure_non_negative_skip>
+class EpsCopyParser {
+ public:
+ EpsCopyParser(ParseClosure parser, ParseContext* ctx) : ctx_(ctx) {
+ ctx_->StartParse(parser);
+ }
+
+ // Parse the bytes as provided by the non-empty range.
+ // Returns true on a successful parse ready to accept more data, if there is
+ // no more data call Done() to finish the parse.
+ // Returns false if the parse is terminated. Termination is either due to a
+ // parse error or due to termination on an end-group or 0 tag. You can call
+ // EndedOnTag() on the underlying ParseContext to find out if the parse ended
+ // correctly on a terminating tag.
+ bool Parse(StringPiece range) {
+ ABSL_ASSERT(!range.empty());
+ auto size = range.size();
+ if (size > kSlopBytes) {
+ // The buffer is large enough to be able to parse the (size - kSlopBytes)
+ // prefix directly. However we still need to parse the data in buffer_,
+ // that holds the slop region of the previous buffer.
+ if (overrun_ == kSlopBytes) {
+ // We overrun the whole slop region of the previous buffer.
+ // Optimization, we can skip the patch buffer.
+ overrun_ = 0;
+ } else {
+ std::memcpy(buffer_ + kSlopBytes, range.begin(), kSlopBytes);
+ if (!ParseRange({buffer_, kSlopBytes}, 0)) return false;
+ }
+ range.remove_suffix(kSlopBytes);
+ } else {
+ std::memcpy(buffer_ + kSlopBytes, range.begin(), size);
+ range = {buffer_, size};
+ }
+ if (!ParseRange(range, size - kSlopBytes)) return false;
+ std::memmove(buffer_, range.end(), kSlopBytes);
+ if (ensure_non_negative_skip &&
+ ctx_->ParseEndsInSlopRegion(buffer_, overrun_)) {
+ // We care about leaving the stream at the right place and the stream will
+ // indeed terminate, so just parse it.
+ auto res = ParseRange({buffer_, kSlopBytes}, size);
+ ABSL_ASSERT(!res);
+ return false;
+ }
+ return true;
+ }
+
+ // Finish the parse by parsing the remaining data and verify success.
+ bool Done() {
+ return ParseRange({buffer_, kSlopBytes}, 0) && ctx_->ValidEnd(overrun_);
+ }
+
+ // If the parse was terminated by a end-group or 0 tag. Skip returns the
+ // offset where the parse left off relative to the start of the last range
+ // parsed.
+ // NOTE: This could be negative unless ensure_non_negative_skip is true.
+ int Skip() {
+ // The reason of ensure_non_negative_skip and ParseEndsInSlopRegion is that
+ // the following assert holds. Which implies the stream doesn't need to
+ // backup.
+ ABSL_ASSERT(!ensure_non_negative_skip || overrun_ >= 0);
+ return overrun_;
+ }
+
+ private:
+ constexpr static int kSlopBytes = ParseContext::kSlopBytes;
+ // overrun_ stores where in the slop region of the previous parse the parse
+ // was left off. This is used to start the parse of the next region at the
+ // correct point. Initially overrun_ should be set to kSlopBytes which means
+ // that the parse starts at precisely the beginning of new buffer provided.
+ int overrun_ = kSlopBytes;
+ // The first kSlopBytes of buffer_ contains the slop region of the previous
+ // parsed region.
+ char buffer_[2 * kSlopBytes] = {};
+ ParseContext* ctx_;
+
+ bool ParseRange(StringPiece range, int delta) {
+ auto res = ctx_->ParseRange(range, &overrun_);
+ if (!res) overrun_ += delta;
+ return res;
+ }
+};
+
+// Add any of the following lines to debug which parse function is failing.
+
+#define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
+ if (!(predicate)) { \
+ /* raise(SIGINT); */ \
+ /* GOOGLE_LOG(ERROR) << "Parse failure"; */ \
+ return ret; \
+ }
+
+#define GOOGLE_PROTOBUF_PARSER_ASSERT(predicate) \
+ GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
+
+template <typename T>
+std::pair<const char*, bool> FieldParser(uint64 tag, ParseClosure parent,
+ T field_parser, const char* begin,
+ const char* end, ParseContext* ctx) {
+ auto ptr = begin;
+ uint32 number = tag >> 3;
+ if (ABSL_PREDICT_FALSE(number == 0)) {
+ GOOGLE_PROTOBUF_ASSERT_RETURN(tag == 0, {});
+ // Special case scenario of 0 termination.
+ ctx->EndGroup(tag);
+ return {ptr, true};
+ }
+ using WireType = internal::WireFormatLite::WireType;
+ switch (tag & 7) {
+ case WireType::WIRETYPE_VARINT: {
+ uint64 value;
+ ptr = Varint::Parse64(ptr, &value);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+ field_parser.AddVarint(number, value);
+ break;
+ }
+ case WireType::WIRETYPE_FIXED64: {
+ uint64 value = io::UnalignedLoad<uint64>(ptr);
+ ptr += 8;
+ field_parser.AddFixed64(number, value);
+ break;
+ }
+ case WireType::WIRETYPE_LENGTH_DELIMITED: {
+ uint32 size;
+ ptr = Varint::Parse32(ptr, &size);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+ ParseClosure child = field_parser.AddLengthDelimited(number, size);
+ if (size > end - ptr) {
+ return {ctx->StoreAndTailCall(ptr, end, parent, child, size), true};
+ }
+ auto newend = ptr + size;
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ctx->ParseExactRange(child, ptr, newend),
+ {});
+ ptr = newend;
+ break;
+ }
+ case WireType::WIRETYPE_START_GROUP: {
+ int depth;
+ ParseClosure child = field_parser.StartGroup(number);
+ auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
+ ptr = res.first;
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+ if (res.second) {
+ GOOGLE_PROTOBUF_ASSERT_RETURN(
+ ctx->StoreGroup(parent, child, depth, tag), {});
+ return {ptr, true};
+ }
+ break;
+ }
+ case WireType::WIRETYPE_END_GROUP: {
+ field_parser.EndGroup(number);
+ ctx->EndGroup(tag);
+ return {ptr, true};
+ }
+ case WireType::WIRETYPE_FIXED32: {
+ uint32 value = io::UnalignedLoad<uint32>(ptr);
+ ptr += 4;
+ field_parser.AddFixed32(number, value);
+ break;
+ }
+ default:
+ GOOGLE_PROTOBUF_ASSERT_RETURN(false, {});
+ }
+ ABSL_ASSERT(ptr != nullptr);
+ return {ptr, false};
+}
+
+template <typename T>
+const char* WireFormatParser(ParseClosure parent, T field_parser,
+ const char* begin, const char* end,
+ ParseContext* ctx) {
+ auto ptr = begin;
+ while (ptr < end) {
+ uint32 tag;
+ ptr = Varint::Parse32(ptr, &tag);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+ auto res = FieldParser(tag, parent, field_parser, ptr, end, ctx);
+ ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+ if (res.second) return ptr;
+ }
+ return ptr;
+}
+
+// Here are the elementary parsers for length delimited subfields that contain
+// plain data (ie not a protobuf). These are trivial as they don't recurse,
+// except for the UnknownGroupLiteParse that parses a group into a string.
+// Some functions need extra arguments that the function signature allows,
+// these are passed through variables in ParseContext::ExtraParseData that the
+// caller needs to set prior to the call.
+
+// The null parser does not do anything, but is useful as a substitute.
+const char* NullParser(const char* begin, const char* end, void* object,
+ ParseContext*);
+
+// Helper for verification of utf8
+bool VerifyUTF8(StringPiece s, ParseContext* ctx);
+// All the string parsers with or without UTF checking and for all CTypes.
+const char* StringParser(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* CordParser(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* StringPieceParser(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* StringParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* CordParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* StringPieceParserUTF8(const char* begin, const char* end,
+ void* object, ParseContext*);
+const char* StringParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext*);
+const char* CordParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext*);
+const char* StringPieceParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext*);
+// Parsers that also eat the slopbytes if possible. Can only be called in a
+// ParseContext where limit_ is set properly.
+const char* GreedyStringParser(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
+ ParseContext*);
+const char* GreedyStringParserUTF8Verify(const char* begin, const char* end,
+ void* object, ParseContext*);
+
+// This is the only recursive parser.
+const char* UnknownGroupLiteParse(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+// This is a helper to for the UnknownGroupLiteParse but is actually also
+// useful in the generated code. It uses overload on string* vs
+// UnknownFieldSet* to make the generated code isomorphic between full and lite.
+std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
+ const char* begin,
+ const char* end, std::string* unknown,
+ ParseContext* ctx);
+
+// The packed parsers parse repeated numeric primitives directly into the
+// corresponding field
+
+// These are packed varints
+const char* PackedInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedBoolParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+
+// Enums in proto3 do not require verification
+const char* PackedEnumParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+// Enums in proto2 require verification. So an additional verification function
+// needs to be passed into ExtraParseData.
+// If it's a generated verification function we only need the function pointer.
+const char* PackedValidEnumParserLite(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+// If it's reflective we need a function that takes an additional argument.
+const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+
+// These are the packed fixed field parsers.
+const char* PackedFixed32Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+const char* PackedSFixed32Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+const char* PackedFixed64Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+const char* PackedSFixed64Parser(const char* begin, const char* end,
+ void* object, ParseContext* ctx);
+const char* PackedFloatParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+const char* PackedDoubleParser(const char* begin, const char* end, void* object,
+ ParseContext* ctx);
+
+// Maps key/value's are stored in a MapEntry length delimited field. If this
+// crosses a seam we fallback to first store in payload. The object points
+// to a MapField in which we parse the payload upon done (we detect this when
+// this function is called with limit_ == 0), by calling parse_map (also stored
+// in ctx) on the resulting string.
+const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
+ internal::ParseContext* ctx);
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+#endif // GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 113605f..65d0821 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -82,6 +82,9 @@
#ifdef PROTOBUF_RETURNS_NONNULL
#error PROTOBUF_RETURNS_NONNULL was previously defined
#endif
+#ifdef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#error PROTOBUF_ATTRIBUTE_REINITIALIZES was previously defined
+#endif
#ifdef PROTOBUF_RTTI
#error PROTOBUF_RTTI was previously defined
#endif
@@ -206,9 +209,20 @@
#else
#ifdef __GNUC__
#define PROTOBUF_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define PROTOBUF_RETURNS_NONNULL
#endif
#endif
+#if defined(__has_cpp_attribute)
+#if __has_cpp_attribute(clang::reinitializes)
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#endif
+#endif
+#ifndef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES
+#endif
+
#define PROTOBUF_GUARDED_BY(x)
#define PROTOBUF_COLD
@@ -306,3 +320,10 @@
#pragma push_macro("GetMessage")
#undef GetMessage
#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+// TODO(gerbens) ideally we cleanup the code. But a cursory try shows many
+// violations. So let's ignore for now.
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index 84eecf5..b3177cd 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -31,6 +31,9 @@
// #undefs all macros defined in port_def.inc. See comments in port_def.inc
// for more info.
+#ifndef PROTOBUF_NAMESPACE
+#error "port_undef.inc must be included after port_def.inc"
+#endif
#undef PROTOBUF_NAMESPACE
#undef PROTOBUF_NAMESPACE_ID
#undef PROTOBUF_ALWAYS_INLINE
@@ -41,6 +44,7 @@
#undef PROTOBUF_DEPRECATED_MSG
#undef PROTOBUF_FUNC_ALIGN
#undef PROTOBUF_RETURNS_NONNULL
+#undef PROTOBUF_ATTRIBUTE_REINITIALIZES
#undef PROTOBUF_RTTI
#undef PROTOBUF_VERSION
#undef PROTOBUF_VERSION_SUFFIX
@@ -60,3 +64,7 @@
#ifdef _MSC_VER
#pragma pop_macro("GetMessage")
#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index f028b2b..233ba7d 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -84,6 +84,19 @@
const FieldDescriptor* field = fields[i];
if (field->is_repeated()) {
+ if (field->is_map()) {
+ MapFieldBase* from_field =
+ from_reflection->MapData(const_cast<Message*>(&from), field);
+ MapFieldBase* to_field =
+ to_reflection->MapData(const_cast<Message*>(to), field);
+ // Use map reflection if both are in map status and have the
+ // same map type to avoid sync with repeated field.
+ if (to_field->IsMapValid() && from_field->IsMapValid()
+ && typeid(*from_field) == typeid(*to_field)) {
+ to_field->MergeFrom(*from_field);
+ continue;
+ }
+ }
int count = from_reflection->FieldSize(from, field);
for (int j = 0; j < count; j++) {
switch (field->cpp_type()) {
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index a3dd41d..1ebde35 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -68,8 +68,7 @@
file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fsource_5fcontext_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto[] =
"\n$google/protobuf/source_context.proto\022\017"
"google.protobuf\"\"\n\rSourceContext\022\021\n\tfile"
"_name\030\001 \001(\tB\225\001\n\023com.google.protobufB\022Sou"
@@ -77,7 +76,10 @@
"proto/protobuf/source_context;source_con"
"text\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTy"
"pesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fsource_5fcontext_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
"google/protobuf/source_context.proto", &assign_descriptors_table_google_2fprotobuf_2fsource_5fcontext_2eproto, 251,
};
@@ -161,10 +163,10 @@
auto msg = static_cast<SourceContext*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -174,26 +176,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.SourceContext.file_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_file_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_file_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -204,7 +209,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index b6fed22..5c5fe86 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -118,7 +118,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const SourceContext& from);
void MergeFrom(const SourceContext& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 10e33ca..6472923 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -137,8 +137,7 @@
file_level_metadata_google_2fprotobuf_2fstruct_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto, file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fstruct_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto[] =
"\n\034google/protobuf/struct.proto\022\017google.p"
"rotobuf\"\204\001\n\006Struct\0223\n\006fields\030\001 \003(\0132#.goo"
"gle.protobuf.Struct.FieldsEntry\032E\n\013Field"
@@ -156,7 +155,10 @@
"protobuf/ptypes/struct;structpb\370\001\001\242\002\003GPB"
"\252\002\036Google.Protobuf.WellKnownTypesb\006proto"
"3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fstruct_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
"google/protobuf/struct.proto", &assign_descriptors_table_google_2fprotobuf_2fstruct_2eproto, 641,
};
@@ -300,10 +302,10 @@
auto msg = static_cast<Struct*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -329,13 +331,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -346,7 +348,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -849,10 +851,10 @@
auto msg = static_cast<Value*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -881,14 +883,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Value.string_value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_string_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_string_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// bool bool_value = 4;
@@ -934,13 +939,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -951,7 +956,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1413,10 +1418,10 @@
auto msg = static_cast<ListValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1441,13 +1446,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1458,7 +1463,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 224fe81..3aa798a 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -185,7 +185,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Struct& from);
void MergeFrom(const Struct& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -330,7 +330,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Value& from);
void MergeFrom(const Value& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -548,7 +548,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const ListValue& from);
void MergeFrom(const ListValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index 7cce442..ab4a3aa 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -373,12 +373,12 @@
};
template <typename R, typename T, typename P1, typename P2, typename P3,
- typename P4, typename P5, typename A1, typename A2>
-class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> {
+ typename P4, typename P5, typename P6, typename A1, typename A2>
+class MethodResultCallback_6_2 : public ResultCallback2<R, A1, A2> {
public:
- typedef R (T::*MethodType)(P1, P2, P3, P4, P5, A1, A2);
- MethodResultCallback_5_2(T* object, MethodType method, bool self_deleting,
- P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+ typedef R (T::*MethodType)(P1, P2, P3, P4, P5, P6, A1, A2);
+ MethodResultCallback_6_2(T* object, MethodType method, bool self_deleting,
+ P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
: object_(object),
method_(method),
self_deleting_(self_deleting),
@@ -386,12 +386,13 @@
p2_(p2),
p3_(p3),
p4_(p4),
- p5_(p5) {}
- ~MethodResultCallback_5_2() {}
+ p5_(p5),
+ p6_(p6) {}
+ ~MethodResultCallback_6_2() {}
R Run(A1 a1, A2 a2) override {
bool needs_delete = self_deleting_;
- R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, a1, a2);
+ R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, p6_, a1, a2);
if (needs_delete) delete this;
return result;
}
@@ -405,6 +406,7 @@
typename std::remove_reference<P3>::type p3_;
typename std::remove_reference<P4>::type p4_;
typename std::remove_reference<P5>::type p5_;
+ typename std::remove_reference<P6>::type p6_;
};
} // namespace internal
@@ -553,19 +555,20 @@
return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
}
-// See MethodResultCallback_5_2
+// See MethodResultCallback_6_2
template <typename R, typename T, typename P1, typename P2, typename P3,
- typename P4, typename P5, typename A1, typename A2>
+ typename P4, typename P5, typename P6, typename A1, typename A2>
inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
- T* object, R (T::*function)(P1, P2, P3, P4, P5, A1, A2),
+ T* object, R (T::*function)(P1, P2, P3, P4, P5, P6, A1, A2),
typename internal::InternalConstRef<P1>::type p1,
typename internal::InternalConstRef<P2>::type p2,
typename internal::InternalConstRef<P3>::type p3,
typename internal::InternalConstRef<P4>::type p4,
- typename internal::InternalConstRef<P5>::type p5) {
- return new internal::MethodResultCallback_5_2<R, T, P1, P2, P3, P4, P5, A1,
- A2>(object, function, false, p1,
- p2, p3, p4, p5);
+ typename internal::InternalConstRef<P5>::type p5,
+ typename internal::InternalConstRef<P6>::type p6) {
+ return new internal::MethodResultCallback_6_2<R, T, P1, P2, P3, P4, P5, P6,
+ A1, A2>(object, function, false,
+ p1, p2, p3, p4, p5, p6);
}
// A function which does nothing. Useful for creating no-op callbacks, e.g.:
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index f1a688d..8e330e0 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -32,6 +32,7 @@
#include <google/protobuf/stubs/common.h>
+#include <atomic>
#include <errno.h>
#include <sstream>
#include <stdio.h>
@@ -180,22 +181,7 @@
}
static LogHandler* log_handler_ = &DefaultLogHandler;
-static int log_silencer_count_ = 0;
-
-static Mutex* log_silencer_count_mutex_ = nullptr;
-GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_);
-
-void DeleteLogSilencerCount() {
- delete log_silencer_count_mutex_;
- log_silencer_count_mutex_ = nullptr;
-}
-void InitLogSilencerCount() {
- log_silencer_count_mutex_ = new Mutex;
- OnShutdown(&DeleteLogSilencerCount);
-}
-void InitLogSilencerCountOnce() {
- GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
-}
+static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0);
LogMessage& LogMessage::operator<<(const string& value) {
message_ += value;
@@ -261,8 +247,6 @@
bool suppress = false;
if (level_ != LOGLEVEL_FATAL) {
- InitLogSilencerCountOnce();
- MutexLock lock(log_silencer_count_mutex_);
suppress = log_silencer_count_ > 0;
}
@@ -299,14 +283,10 @@
}
LogSilencer::LogSilencer() {
- internal::InitLogSilencerCountOnce();
- MutexLock lock(internal::log_silencer_count_mutex_);
++internal::log_silencer_count_;
};
LogSilencer::~LogSilencer() {
- internal::InitLogSilencerCountOnce();
- MutexLock lock(internal::log_silencer_count_mutex_);
--internal::log_silencer_count_;
};
diff --git a/src/google/protobuf/stubs/io_win32.h b/src/google/protobuf/stubs/io_win32.h
index afa5de3..69924dc 100644
--- a/src/google/protobuf/stubs/io_win32.h
+++ b/src/google/protobuf/stubs/io_win32.h
@@ -111,8 +111,8 @@
#define STDOUT_FILENO 1
#endif
-#endif // defined(_WIN32)
-
#include <google/protobuf/port_undef.inc>
+#endif // defined(_WIN32)
+
#endif // GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__
diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h
index f3835cc..feb71c1 100644
--- a/src/google/protobuf/stubs/once.h
+++ b/src/google/protobuf/stubs/once.h
@@ -28,53 +28,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Author: kenton@google.com (Kenton Varda)
-//
-// emulates google3/base/once.h
-//
-// This header is intended to be included only by internal .cc files and
-// generated .pb.cc files. Users should not use this directly.
-//
-// This is basically a portable version of pthread_once().
-//
-// This header declares:
-// * A type called ProtobufOnceType.
-// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
-// ProtobufOnceType. This is the only legal way to declare such a variable.
-// The macro may only be used at the global scope (you cannot create local or
-// class member variables of this type).
-// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
-// This function, when invoked multiple times given the same ProtobufOnceType
-// object, will invoke init_func on the first call only, and will make sure
-// none of the calls return before that first call to init_func has finished.
-// * The user can provide a parameter which GoogleOnceInit() forwards to the
-// user-provided function when it is called. Usage example:
-// int a = 10;
-// GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
-// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
-// static initializer generated).
-//
-// This implements a way to perform lazy initialization. It's more efficient
-// than using mutexes as no lock is needed if initialization has already
-// happened.
-//
-// Example usage:
-// void Init();
-// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
-//
-// // Calls Init() exactly once.
-// void InitOnce() {
-// GoogleOnceInit(&once_init, &Init);
-// }
-//
-// Note that if GoogleOnceInit() is called before main() has begun, it must
-// only be called by the thread that will eventually call main() -- that is,
-// the thread that performs dynamic initialization. In general this is a safe
-// assumption since people don't usually construct threads before main() starts,
-// but it is technically not guaranteed. Unfortunately, Win32 provides no way
-// whatsoever to statically-initialize its synchronization primitives, so our
-// only choice is to assume that dynamic initialization is single-threaded.
-
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
@@ -93,37 +46,6 @@
} // namespace internal
-// TODO(gerbens) remove this once third_party is fully extracted
-using ProtobufOnceType = internal::once_flag;
-
-inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
- std::call_once(*once, init_func);
-}
-
-template <typename Arg>
-inline void GoogleOnceInitArg(ProtobufOnceType* once, void (*init_func)(Arg*),
- Arg* arg) {
- std::call_once(*once, init_func, arg);
-}
-
-class GoogleOnceDynamic {
- public:
- // If this->Init() has not been called before by any thread,
- // execute (*func_with_arg)(arg) then return.
- // Otherwise, wait until that prior invocation has finished
- // executing its function, then return.
- template<typename T>
- void Init(void (*func_with_arg)(T*), T* arg) {
- GoogleOnceInitArg<T>(&this->state_, func_with_arg, arg);
- }
- private:
- ProtobufOnceType state_;
-};
-
-#define GOOGLE_PROTOBUF_ONCE_TYPE ::google::protobuf::ProtobufOnceType
-#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
- ::google::protobuf::ProtobufOnceType NAME
-
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/stubs/status.h b/src/google/protobuf/stubs/status.h
index 008416e..440a0ed 100644
--- a/src/google/protobuf/stubs/status.h
+++ b/src/google/protobuf/stubs/status.h
@@ -90,9 +90,15 @@
int error_code() const {
return error_code_;
}
+ error::Code code() const {
+ return error_code_;
+ }
StringPiece error_message() const {
return error_message_;
}
+ StringPiece message() const {
+ return error_message_;
+ }
bool operator==(const Status& x) const;
bool operator!=(const Status& x) const {
diff --git a/src/google/protobuf/stubs/status_test.cc b/src/google/protobuf/stubs/status_test.cc
index c70c33c..9a18778 100644
--- a/src/google/protobuf/stubs/status_test.cc
+++ b/src/google/protobuf/stubs/status_test.cc
@@ -40,13 +40,17 @@
TEST(Status, Empty) {
util::Status status;
EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+ EXPECT_EQ(util::error::OK, util::Status::OK.code());
EXPECT_EQ("OK", util::Status::OK.ToString());
}
TEST(Status, GenericCodes) {
EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+ EXPECT_EQ(util::error::OK, util::Status::OK.code());
EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.error_code());
+ EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.code());
EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.error_code());
+ EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.code());
}
TEST(Status, ConstructorZero) {
@@ -66,14 +70,17 @@
util::Status status(util::error::INVALID_ARGUMENT, "");
EXPECT_FALSE(status.ok());
EXPECT_EQ("", status.error_message().ToString());
+ EXPECT_EQ("", status.message().ToString());
EXPECT_EQ("INVALID_ARGUMENT", status.ToString());
status = util::Status(util::error::INVALID_ARGUMENT, "msg");
EXPECT_FALSE(status.ok());
EXPECT_EQ("msg", status.error_message().ToString());
+ EXPECT_EQ("msg", status.message().ToString());
EXPECT_EQ("INVALID_ARGUMENT:msg", status.ToString());
status = util::Status(util::error::OK, "msg");
EXPECT_TRUE(status.ok());
EXPECT_EQ("", status.error_message().ToString());
+ EXPECT_EQ("", status.message().ToString());
EXPECT_EQ("OK", status.ToString());
}
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index c8de875..a434509 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -32,17 +32,16 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
-#include <algorithm>
-#include <climits>
+#include <google/protobuf/text_format.h>
+
#include <float.h>
#include <math.h>
#include <stdio.h>
-#include <stack>
+#include <algorithm>
+#include <climits>
#include <limits>
#include <vector>
-#include <google/protobuf/text_format.h>
-
#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/any.h>
#include <google/protobuf/descriptor.pb.h>
@@ -61,7 +60,6 @@
-
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
@@ -446,8 +444,8 @@
descriptor->full_name() + "\".");
return false;
} else {
- ReportWarning("Extension \"" + field_name + "\" is not defined or "
- "is not an extension of \"" +
+ ReportWarning("Ignoring extension \"" + field_name +
+ "\" which is not defined or is not an extension of \"" +
descriptor->full_name() + "\".");
}
}
@@ -847,6 +845,8 @@
if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
!LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+ string text = tokenizer_.current().text;
+ ReportError("Cannot skip field value, unexpected token: " + text);
return false;
}
// Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 4a962e3..04684b6 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -69,15 +69,17 @@
file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
- false, InitDefaults_google_2fprotobuf_2ftimestamp_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto[] =
"\n\037google/protobuf/timestamp.proto\022\017googl"
"e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
"\022\r\n\005nanos\030\002 \001(\005B~\n\023com.google.protobufB\016"
"TimestampProtoP\001Z+github.com/golang/prot"
"obuf/ptypes/timestamp\370\001\001\242\002\003GPB\252\002\036Google."
"Protobuf.WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2ftimestamp_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
"google/protobuf/timestamp.proto", &assign_descriptors_table_google_2fprotobuf_2ftimestamp_2eproto, 231,
};
@@ -176,10 +178,10 @@
auto msg = static_cast<Timestamp*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -206,13 +208,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -223,7 +225,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 9839e92..2335796 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -125,7 +125,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Timestamp& from);
void MergeFrom(const Timestamp& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
index 05d988a..2b9e26a 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -113,7 +113,7 @@
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
-// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 2d00a8f..01b86a5 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -211,8 +211,7 @@
file_level_metadata_google_2fprotobuf_2ftype_2eproto, 5, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
- false, InitDefaults_google_2fprotobuf_2ftype_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] =
"\n\032google/protobuf/type.proto\022\017google.pro"
"tobuf\032\031google/protobuf/any.proto\032$google"
"/protobuf/source_context.proto\"\327\001\n\004Type\022"
@@ -253,7 +252,10 @@
"ufB\tTypeProtoP\001Z/google.golang.org/genpr"
"oto/protobuf/ptype;ptype\370\001\001\242\002\003GPB\252\002\036Goog"
"le.Protobuf.WellKnownTypesb\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2ftype_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
"google/protobuf/type.proto", &assign_descriptors_table_google_2fprotobuf_2ftype_2eproto, 1594,
};
@@ -503,10 +505,10 @@
auto msg = static_cast<Type*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -516,14 +518,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Type.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.Field fields = 2;
@@ -551,14 +556,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Type.oneofs");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->add_oneofs();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->add_oneofs();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
if (ptr >= end) break;
} while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
break;
@@ -609,13 +617,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -626,7 +634,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1154,10 +1162,10 @@
auto msg = static_cast<Field*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1197,14 +1205,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Field.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// string type_url = 6;
@@ -1213,14 +1224,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Field.type_url");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_type_url();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_type_url();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// int32 oneof_index = 7;
@@ -1267,14 +1281,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Field.json_name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_json_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_json_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// string default_value = 11;
@@ -1283,26 +1300,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Field.default_value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_default_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_default_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1313,7 +1333,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2005,10 +2025,10 @@
auto msg = static_cast<Enum*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -2018,14 +2038,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Enum.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// repeated .google.protobuf.EnumValue enumvalue = 2;
@@ -2092,13 +2115,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2109,7 +2132,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2554,10 +2577,10 @@
auto msg = static_cast<EnumValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -2567,14 +2590,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValue.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// int32 number = 2;
@@ -2608,13 +2634,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2625,7 +2651,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3022,10 +3048,10 @@
auto msg = static_cast<Option*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -3035,14 +3061,17 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Option.name");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_name();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_name();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
// .google.protobuf.Any value = 2;
@@ -3063,13 +3092,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -3080,7 +3109,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 63d71e6..3c72010 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -226,7 +226,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Type& from);
void MergeFrom(const Type& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -438,7 +438,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Field& from);
void MergeFrom(const Field& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -791,7 +791,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Enum& from);
void MergeFrom(const Enum& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -980,7 +980,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const EnumValue& from);
void MergeFrom(const EnumValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1143,7 +1143,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Option& from);
void MergeFrom(const Option& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 0226c76..fe3c825 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -352,23 +352,38 @@
return ptr;
}
+class UnknownFieldParserHelper {
+ public:
+ explicit UnknownFieldParserHelper(UnknownFieldSet* unknown)
+ : unknown_(unknown) {}
+
+ void AddVarint(uint32 num, uint64 value) { unknown_->AddVarint(num, value); }
+ void AddFixed64(uint32 num, uint64 value) {
+ unknown_->AddFixed64(num, value);
+ }
+ ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
+ string* s = unknown_->AddLengthDelimited(num);
+ // TODO(gerbens) SECURITY: add security
+ s->reserve(size);
+ return {GreedyStringParser, s};
+ }
+ ParseClosure StartGroup(uint32 num) {
+ return {UnknownGroupParse, unknown_->AddGroup(num)};
+ }
+ void EndGroup(uint32 num) {}
+ void AddFixed32(uint32 num, uint32 value) {
+ unknown_->AddFixed32(num, value);
+ }
+
+ private:
+ UnknownFieldSet* unknown_;
+};
+
const char* UnknownGroupParse(const char* begin, const char* end, void* object,
ParseContext* ctx) {
- auto unknown = static_cast<UnknownFieldSet*>(object);
-
- auto ptr = begin;
- while (ptr < end) {
- uint32 tag;
- ptr = Varint::Parse32Inline(ptr, &tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- GOOGLE_PROTOBUF_PARSER_ASSERT((tag >> 3) != 0);
-
- auto res = UnknownFieldParse(tag, {UnknownGroupParse, unknown}, ptr, end,
- unknown, ctx);
- ptr = res.first;
- if (res.second) break;
- }
- return ptr;
+ UnknownFieldParserHelper field_parser(static_cast<UnknownFieldSet*>(object));
+ return WireFormatParser({UnknownGroupParse, object}, field_parser, begin, end,
+ ctx);
}
std::pair<const char*, bool> UnknownFieldParse(uint64 tag, ParseClosure parent,
@@ -376,73 +391,8 @@
const char* end,
UnknownFieldSet* unknown,
ParseContext* ctx) {
- uint32 size;
- int depth;
- void* object;
- auto ptr = begin;
-
- uint32 field_num = tag >> 3;
- GOOGLE_PROTOBUF_ASSERT_RETURN(field_num != 0, std::make_pair(nullptr, true));
- switch (tag & 7) {
- case 0: {
- uint64 val;
- ptr = Varint::Parse64(ptr, &val);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- unknown->AddVarint(field_num, val);
- break;
- }
- case 1: {
- uint64 val = UNALIGNED_LOAD64(ptr);
- ptr = ptr + 8;
- unknown->AddFixed64(field_num, val);
- break;
- }
- case 2: {
- ptr = Varint::Parse32Inline(ptr, &size);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- object = unknown->AddLengthDelimited(field_num);
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- bool ok = ctx->ParseExactRange({StringParser, object}, ptr, newend);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = newend;
- break;
- }
- case 3: {
- object = unknown->AddGroup(field_num);
- bool ok = ctx->PrepareGroup(tag, &depth);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- ptr = UnknownGroupParse(ptr, end, object, ctx);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
- if (ctx->GroupContinues(depth)) goto group_continues;
- break;
- }
- case 4: {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
- return std::make_pair(ptr, true);
- }
- case 5: {
- uint32 val = UNALIGNED_LOAD32(ptr);
- ptr = ptr + 4;
- unknown->AddFixed32(field_num, val);
- break;
- }
- default:
- GOOGLE_PROTOBUF_ASSERT_RETURN(false, std::make_pair(nullptr, true));
- }
- return std::make_pair(ptr, false);
-len_delim_till_end:
- // Length delimited field crosses end
- return std::make_pair(
- ctx->StoreAndTailCall(ptr, end, parent, {StringParser, object}, size),
- true);
-group_continues:
- GOOGLE_DCHECK(ptr >= end);
- // Group crossed end and must be continued. Either this a parse failure
- // or we need to resume on the next chunk and thus save the state.
- ctx->StoreGroup(parent, {UnknownGroupParse, object}, depth);
- return std::make_pair(ptr, true);
+ UnknownFieldParserHelper field_parser(unknown);
+ return FieldParser(tag, parent, field_parser, begin, end, ctx);
}
} // namespace internal
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 7ba33da..0193b27 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -43,16 +43,13 @@
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/port.h>
#include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index 72b7d17..30060fe 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -367,7 +367,7 @@
WebSafeBase64Escape(*dest, &encoded);
// Remove trailing padding '=' characters before comparison.
StringPiece src_no_padding = StringPiece(src).substr(
- 0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1
+ 0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
: src.length());
return encoded == src_no_padding;
}
@@ -381,7 +381,7 @@
reinterpret_cast<const unsigned char*>(dest->data()), dest->length(),
&encoded, false);
StringPiece src_no_padding = StringPiece(src).substr(
- 0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1
+ 0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
: src.length());
return encoded == src_no_padding;
}
diff --git a/src/google/protobuf/util/internal/expecting_objectwriter.h b/src/google/protobuf/util/internal/expecting_objectwriter.h
index 108a15b..7bc47a3 100644
--- a/src/google/protobuf/util/internal/expecting_objectwriter.h
+++ b/src/google/protobuf/util/internal/expecting_objectwriter.h
@@ -53,7 +53,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/object_writer.h>
#include <gmock/gmock.h>
-
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc
index b019012..669c051 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.cc
+++ b/src/google/protobuf/util/internal/field_mask_utility.cc
@@ -42,10 +42,6 @@
namespace converter {
namespace {
-inline util::Status CallPathSink(PathSinkCallback path_sink,
- StringPiece arg) {
- return path_sink->Run(arg);
-}
// Appends a FieldMask path segment to a prefix.
string AppendPathSegmentToPrefix(StringPiece prefix,
@@ -57,7 +53,7 @@
return string(prefix);
}
// If the segment is a map key, appends it to the prefix without the ".".
- if (StringStartsWith(segment, "[\"")) {
+ if (HasPrefixString(segment, "[\"")) {
return StrCat(prefix, segment);
}
return StrCat(prefix, ".", segment);
@@ -192,8 +188,8 @@
// When the current charactor is ')', ',' or the current position has
// passed the end of the input, builds and outputs a new paths by
// concatenating the last prefix with the current segment.
- RETURN_IF_ERROR(CallPathSink(
- path_sink, AppendPathSegmentToPrefix(current_prefix, segment)));
+ RETURN_IF_ERROR(
+ path_sink(AppendPathSegmentToPrefix(current_prefix, segment)));
}
// Removes the last prefix after seeing a ')'.
diff --git a/src/google/protobuf/util/internal/field_mask_utility.h b/src/google/protobuf/util/internal/field_mask_utility.h
index c2afbd5..a10b1ec 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.h
+++ b/src/google/protobuf/util/internal/field_mask_utility.h
@@ -46,8 +46,8 @@
namespace util {
namespace converter {
-typedef std::string (*ConverterCallback)(StringPiece);
-typedef ResultCallback1<util::Status, StringPiece>* PathSinkCallback;
+typedef std::function<std::string(StringPiece)> ConverterCallback;
+typedef std::function<util::Status(StringPiece)> PathSinkCallback;
// Applies a 'converter' to each segment of a FieldMask path and returns the
// result. Quoted strings in the 'path' are copied to the output as-is without
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index e272bbd..687f9e7 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -249,7 +249,8 @@
}
if (!result.ok()) {
// If we were cancelled, save our state and try again later.
- if (!finishing_ && result == util::Status(error::CANCELLED, "")) {
+ if (!finishing_ &&
+ result == util::Status(util::error::CANCELLED, "")) {
stack_.push(type);
// If we have a key we still need to render, make sure to save off the
// contents in our own storage.
@@ -293,7 +294,7 @@
// don't know if the next char would be e, completing it, or something
// else, making it invalid.
if (!finishing_ && p_.length() < false_len) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
return ReportFailure("Unexpected token.");
}
@@ -331,7 +332,7 @@
// depending on if we expect more data later.
if (p_.length() == 1) {
if (!finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
return ReportFailure("Closing quote expected in string.");
}
@@ -399,7 +400,7 @@
}
// If we didn't find the closing quote but we expect more data, cancel for now
if (!finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
// End of string reached without a closing quote, report an error.
string_open_ = 0;
@@ -416,7 +417,7 @@
util::Status JsonStreamParser::ParseUnicodeEscape() {
if (p_.length() < kUnicodeEscapedLength) {
if (!finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
return ReportFailure("Illegal hex string.");
}
@@ -433,7 +434,7 @@
code <= JsonEscaping::kMaxHighSurrogate) {
if (p_.length() < 2 * kUnicodeEscapedLength) {
if (!finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
if (!coerce_to_utf8_) {
return ReportFailure("Missing low surrogate.");
@@ -540,7 +541,7 @@
// If the entire input is a valid number, and we may have more content in the
// future, we abort for now and resume when we know more.
if (index == length && !finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
// Create a string containing just the number, so we can use safe_strtoX
@@ -708,7 +709,7 @@
// empty-null array value is relying on this ARRAY_MID token.
stack_.push(ARRAY_MID);
util::Status result = ParseValue(type);
- if (result == util::Status(error::CANCELLED, "")) {
+ if (result == util::Status(util::error::CANCELLED, "")) {
// If we were cancelled, pop back off the ARRAY_MID so we don't try to
// push it on again when we try over.
stack_.pop();
@@ -787,7 +788,7 @@
util::Status JsonStreamParser::ReportUnknown(StringPiece message) {
// If we aren't finishing the parse, cancel parsing and try later.
if (!finishing_) {
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
if (p_.empty()) {
return ReportFailure(StrCat("Unexpected end of string. ", message));
@@ -828,7 +829,7 @@
// we can't know if the key was complete or not.
if (!finishing_ && p_.empty()) {
p_ = original;
- return util::Status(error::CANCELLED, "");
+ return util::Status(util::error::CANCELLED, "");
}
// Since we aren't using the key storage, clear it out.
key_storage_.clear();
diff --git a/src/google/protobuf/util/internal/mock_error_listener.h b/src/google/protobuf/util/internal/mock_error_listener.h
index 1f1321f..53e5876 100644
--- a/src/google/protobuf/util/internal/mock_error_listener.h
+++ b/src/google/protobuf/util/internal/mock_error_listener.h
@@ -34,7 +34,7 @@
#include <google/protobuf/util/internal/error_listener.h>
#include <google/protobuf/util/internal/location_tracker.h>
#include <gmock/gmock.h>
-
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 56ee774..391c32e 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -386,27 +386,45 @@
}
string ProtoWriter::ProtoElement::ToString() const {
- if (parent() == nullptr) return "";
- string loc = parent()->ToString();
- if (!ow_->IsRepeated(*parent_field_) ||
- parent()->parent_field_ != parent_field_) {
- string name = parent_field_->name();
- int i = 0;
- while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
- if (i > 0 && i == name.size()) { // safe field name
- if (loc.empty()) {
- loc = name;
+ string loc = "";
+
+ // first populate a stack with the nodes since we need to process them
+ // from root to leaf when generating the string location
+ const ProtoWriter::ProtoElement* now = this;
+ std::stack<const ProtoWriter::ProtoElement*> element_stack;
+ while (now->parent() != nullptr) {
+ element_stack.push(now);
+ now = now->parent();
+ }
+
+ // now pop each node from the stack and append to the location string
+ while (!element_stack.empty()) {
+ now = element_stack.top();
+ element_stack.pop();
+
+ if (!ow_->IsRepeated(*(now->parent_field_)) ||
+ now->parent()->parent_field_ != now->parent_field_) {
+ string name = now->parent_field_->name();
+ int i = 0;
+ while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
+ if (i > 0 && i == name.size()) { // safe field name
+ if (loc.empty()) {
+ loc = name;
+ } else {
+ StrAppend(&loc, ".", name);
+ }
} else {
- StrAppend(&loc, ".", name);
+ StrAppend(&loc, "[\"", CEscape(name), "\"]");
}
- } else {
- StrAppend(&loc, "[\"", CEscape(name), "\"]");
+ }
+
+ int array_index_now = now->array_index_;
+ if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) {
+ StrAppend(&loc, "[", array_index_now - 1, "]");
}
}
- if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
- StrAppend(&loc, "[", array_index_ - 1, "]");
- }
- return loc.empty() ? "." : loc;
+
+ return loc;
}
bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
@@ -678,7 +696,8 @@
break;
}
default: // TYPE_GROUP or TYPE_MESSAGE
- status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
+ status = Status(util::error::INVALID_ARGUMENT,
+ data.ToString().ValueOrDie());
}
if (!status.ok()) {
@@ -687,7 +706,7 @@
element_.reset(new ProtoElement(element_.release(), &field, type, false));
}
InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
- status.error_message());
+ status.message());
element_.reset(element()->pop());
return this;
}
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 97a8bb4..55e8e4b 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -49,7 +49,6 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/casts.h>
-
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/status_macros.h>
@@ -128,7 +127,8 @@
max_recursion_depth_(kDefaultMaxRecursionDepth),
render_unknown_fields_(false),
render_unknown_enum_values_(true),
- add_trailing_zeros_for_timestamp_and_duration_(false) {
+ add_trailing_zeros_for_timestamp_and_duration_(false),
+ suppress_empty_object_(false) {
GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
}
@@ -146,7 +146,8 @@
max_recursion_depth_(kDefaultMaxRecursionDepth),
render_unknown_fields_(false),
render_unknown_enum_values_(true),
- add_trailing_zeros_for_timestamp_and_duration_(false) {
+ add_trailing_zeros_for_timestamp_and_duration_(false),
+ suppress_empty_object_(false) {
GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
}
@@ -198,6 +199,10 @@
uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
UnknownFieldSet unknown_fields;
+ if (tag == end_tag && suppress_empty_object_) {
+ return util::Status();
+ }
+
if (include_start_and_end) {
ow->StartObject(name);
}
@@ -640,7 +645,7 @@
// Convert into an internal error, since this means the backend gave us
// an invalid response (missing or invalid type information).
return util::Status(util::error::INTERNAL,
- resolved_type.status().error_message());
+ resolved_type.status().message());
}
// nested_type cannot be null at this time.
const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index c254987..5ff8327 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -325,6 +325,11 @@
// Whether to add trailing zeros for timestamp and duration.
bool add_trailing_zeros_for_timestamp_and_duration_;
+ // Whether output the empty object or not. If false, output JSON string like:
+ // "'objectName' : {}". If true, then no outputs. This only happens when all
+ // the fields of the message are filtered out by field mask.
+ bool suppress_empty_object_;
+
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
};
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 9c52116..f2f0f3f 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -59,6 +59,7 @@
using util::Status;
using util::StatusOr;
using util::error::INVALID_ARGUMENT;
+using std::placeholders::_1;
ProtoStreamObjectWriter::ProtoStreamObjectWriter(
@@ -139,14 +140,14 @@
// conversion to 'nanos', rather than a double, so that there is no
// loss of precision.
if (!s_nanos.empty() && !safe_strto32(s_nanos, &i_nanos)) {
- return Status(INVALID_ARGUMENT, parse_failure_message);
+ return Status(util::error::INVALID_ARGUMENT, parse_failure_message);
}
if (i_nanos > kNanosPerSecond || i_nanos < 0) {
- return Status(INVALID_ARGUMENT, exceeded_limit_message);
+ return Status(util::error::INVALID_ARGUMENT, exceeded_limit_message);
}
// s_nanos should only have digits. No whitespace.
if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
- return Status(INVALID_ARGUMENT, parse_failure_message);
+ return Status(util::error::INVALID_ARGUMENT, parse_failure_message);
}
if (i_nanos > 0) {
@@ -186,7 +187,8 @@
conversion = 1;
break;
default:
- return Status(INVALID_ARGUMENT, exceeded_limit_message);
+ return Status(util::error::INVALID_ARGUMENT,
+ exceeded_limit_message);
}
*nanos = i_nanos * conversion;
}
@@ -311,7 +313,7 @@
} else {
ow_->ProtoWriter::StartObject("");
Status status = (*well_known_type_render_)(ow_.get(), value);
- if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
+ if (!status.ok()) ow_->InvalidValue("Any", status.message());
ow_->ProtoWriter::EndObject();
}
} else {
@@ -327,7 +329,7 @@
} else {
StatusOr<string> s = value.ToString();
if (!s.ok()) {
- parent_->InvalidValue("String", s.status().error_message());
+ parent_->InvalidValue("String", s.status().message());
invalid_ = true;
return;
}
@@ -337,7 +339,7 @@
StatusOr<const google::protobuf::Type*> resolved_type =
parent_->typeinfo()->ResolveTypeUrl(type_url_);
if (!resolved_type.ok()) {
- parent_->InvalidValue("Any", resolved_type.status().error_message());
+ parent_->InvalidValue("Any", resolved_type.status().message());
invalid_ = true;
return;
}
@@ -354,8 +356,9 @@
// Create our object writer and initialize it with the first StartObject
// call.
- ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
- parent_->listener(), parent_->options_));
+ ow_.reset(new ProtoStreamObjectWriter(
+ parent_->typeinfo(), *type, &output_, parent_->listener(),
+ parent_->options_));
// Don't call StartObject() for well-known types yet. Depending on the
// type of actual data, we may not need to call StartObject(). For
@@ -930,7 +933,7 @@
break;
}
default: {
- return Status(INVALID_ARGUMENT,
+ return Status(util::error::INVALID_ARGUMENT,
"Invalid struct data type. Only number, string, boolean or "
"null values are supported.");
}
@@ -943,7 +946,7 @@
const DataPiece& data) {
if (data.type() == DataPiece::TYPE_NULL) return Status();
if (data.type() != DataPiece::TYPE_STRING) {
- return Status(INVALID_ARGUMENT,
+ return Status(util::error::INVALID_ARGUMENT,
StrCat("Invalid data type for timestamp, value is ",
data.ValueAsStringOrDefault("")));
}
@@ -974,7 +977,7 @@
const DataPiece& data) {
if (data.type() == DataPiece::TYPE_NULL) return Status();
if (data.type() != DataPiece::TYPE_STRING) {
- return Status(INVALID_ARGUMENT,
+ return Status(util::error::INVALID_ARGUMENT,
StrCat("Invalid data type for field mask, value is ",
data.ValueAsStringOrDefault("")));
}
@@ -982,29 +985,28 @@
// TODO(tsun): figure out how to do proto descriptor based snake case
// conversions as much as possible. Because ToSnakeCase sometimes returns the
// wrong value.
- std::unique_ptr<ResultCallback1<util::Status, StringPiece>> callback(
- ::google::protobuf::NewPermanentCallback(&RenderOneFieldPath, ow));
- return DecodeCompactFieldMaskPaths(data.str(), callback.get());
+ return DecodeCompactFieldMaskPaths(data.str(),
+ std::bind(&RenderOneFieldPath, ow, _1));
}
Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
const DataPiece& data) {
if (data.type() == DataPiece::TYPE_NULL) return Status();
if (data.type() != DataPiece::TYPE_STRING) {
- return Status(INVALID_ARGUMENT,
+ return Status(util::error::INVALID_ARGUMENT,
StrCat("Invalid data type for duration, value is ",
data.ValueAsStringOrDefault("")));
}
StringPiece value(data.str());
- if (!StringEndsWith(value, "s")) {
- return Status(INVALID_ARGUMENT,
+ if (!HasSuffixString(value, "s")) {
+ return Status(util::error::INVALID_ARGUMENT,
"Illegal duration format; duration must end with 's'");
}
value = value.substr(0, value.size() - 1);
int sign = 1;
- if (StringStartsWith(value, "-")) {
+ if (HasPrefixString(value, "-")) {
sign = -1;
value = value.substr(1);
}
@@ -1013,7 +1015,7 @@
SplitSecondsAndNanos(value, &s_secs, &s_nanos);
uint64 unsigned_seconds;
if (!safe_strtou64(s_secs, &unsigned_seconds)) {
- return Status(INVALID_ARGUMENT,
+ return Status(util::error::INVALID_ARGUMENT,
"Invalid duration format, failed to parse seconds");
}
@@ -1029,7 +1031,8 @@
int64 seconds = sign * unsigned_seconds;
if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
- return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
+ return Status(util::error::INVALID_ARGUMENT,
+ "Duration value exceeds limits");
}
ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
@@ -1063,8 +1066,8 @@
ProtoWriter::StartObject(name);
status = (*type_renderer)(this, data);
if (!status.ok()) {
- InvalidValue(master_type_.name(), StrCat("Field '", name, "', ",
- status.error_message()));
+ InvalidValue(master_type_.name(),
+ StrCat("Field '", name, "', ", status.message()));
}
ProtoWriter::EndObject();
return this;
@@ -1109,8 +1112,8 @@
Push("value", Item::MESSAGE, true, false);
status = (*type_renderer)(this, data);
if (!status.ok()) {
- InvalidValue(field->type_url(), StrCat("Field '", name, "', ",
- status.error_message()));
+ InvalidValue(field->type_url(),
+ StrCat("Field '", name, "', ", status.message()));
}
Pop();
return this;
@@ -1143,8 +1146,8 @@
Push(name, Item::MESSAGE, false, false);
status = (*type_renderer)(this, data);
if (!status.ok()) {
- InvalidValue(field->type_url(), StrCat("Field '", name, "', ",
- status.error_message()));
+ InvalidValue(field->type_url(),
+ StrCat("Field '", name, "', ", status.message()));
}
Pop();
}
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index fe8170d..bdb70c7 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -330,7 +330,7 @@
const google::protobuf::Type& type,
strings::ByteSink* output, ErrorListener* listener);
- ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+ ProtoStreamObjectWriter(const TypeInfo* typeinfo,
const google::protobuf::Type& type,
strings::ByteSink* output, ErrorListener* listener,
const ProtoStreamObjectWriter::Options& options);
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 66a8f00..c464696 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -58,7 +58,6 @@
#include <gtest/gtest.h>
-
namespace google {
namespace protobuf {
namespace util {
diff --git a/src/google/protobuf/util/internal/testdata/anys.proto b/src/google/protobuf/util/internal/testdata/anys.proto
index 77c1043..4749b77 100644
--- a/src/google/protobuf/util/internal/testdata/anys.proto
+++ b/src/google/protobuf/util/internal/testdata/anys.proto
@@ -58,9 +58,13 @@
AnyWrapper any_with_message_containing_repeated_message = 14;
AnyWrapper recursive_any_with_type_field_at_end = 15;
AnyWrapper repeated_any = 16;
+ AnyWrapper empty_any_with_null_type_url = 17;
google.protobuf.Any top_level_any = 50;
google.protobuf.Any top_level_any_with_type_field_at_end = 51;
+ google.protobuf.Any top_level_any_with_pivot_one = 52;
+ google.protobuf.Any top_level_any_with_pivot_two = 53;
+ google.protobuf.Any top_level_any_unordered = 54;
}
message AnyWrapper {
diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto
index 812474b..6068ce6 100644
--- a/src/google/protobuf/util/internal/testdata/books.proto
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -39,6 +39,8 @@
package google.protobuf.testing;
+import "google/protobuf/util/internal/testdata/anys.proto";
+
// A book
message Book {
optional string title = 1;
@@ -72,6 +74,13 @@
// Useful for testing JSON snake/camel-case conversions.
optional string snake_field = 12;
+ // Used to test type not found in type info. Messages defined in other files
+ // are not added when adding Book to type info.
+ optional AnyWrapper type_not_found = 13;
+
+ // Used to test invalid value inside of primitive repeated fields.
+ repeated int32 primitive_repeated = 14;
+
extensions 200 to 499;
}
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 7c7e3f1..49e85a1 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -408,13 +408,6 @@
return true;
}
-bool StringStartsWith(StringPiece text, StringPiece prefix) {
- return text.starts_with(prefix);
-}
-
-bool StringEndsWith(StringPiece text, StringPiece suffix) {
- return text.ends_with(suffix);
-}
} // namespace converter
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 6fe8295..29935d6 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -204,11 +204,6 @@
// value fits into double but not float (e.g., DBL_MAX).
PROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value);
-// Returns whether a StringPiece begins with the provided prefix.
-bool StringStartsWith(StringPiece text, StringPiece prefix);
-
-// Returns whether a StringPiece ends with the provided suffix.
-bool StringEndsWith(StringPiece text, StringPiece suffix);
} // namespace converter
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto
index 40b040e..767611f 100644
--- a/src/google/protobuf/util/json_format.proto
+++ b/src/google/protobuf/util/json_format.proto
@@ -107,3 +107,7 @@
optional int32 value = 1;
optional TestRecursion child = 2;
}
+
+message TestStringMap {
+ map<string, string> string_map = 1;
+}
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 19e20a4..0d2173c 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -44,7 +44,7 @@
#include <google/protobuf/util/type_resolver_util.h>
#include <google/protobuf/stubs/bytestream.h>
-
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/status_macros.h>
#include <google/protobuf/port_def.inc>
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index f62e7f0..015ca58 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -36,7 +36,7 @@
#include <google/protobuf/message.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/stubs/bytestream.h>
-
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index 125d4d4..23da45b 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -363,11 +363,11 @@
"{\n"
" \"value\": {\n"
" \"@type\": \"type.googleapis.com/proto3.TestMessage\",\n"
- " \"unknown_field\": \"UNKOWN_VALUE\",\n"
+ " \"unknown_field\": \"UNKNOWN_VALUE\",\n"
" \"string_value\": \"expected_value\"\n"
" }\n"
"}";
-
+
TestAny m;
JsonParseOptions options;
EXPECT_FALSE(FromJson(input, &m, options));
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index 8a09400..3e00d07 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -58,6 +58,38 @@
namespace util {
+// A reporter to report the total number of diffs.
+// TODO(ykzhu): we can improve this to take into account the value differencers.
+class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Reporter {
+ public:
+ NumDiffsReporter() : num_diffs_(0) {}
+
+ // Returns the total number of diffs.
+ int32 GetNumDiffs() const { return num_diffs_; }
+ void Reset() { num_diffs_ = 0; }
+
+ // Report that a field has been added into Message2.
+ void ReportAdded(
+ const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+ const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+ field_path) override { ++num_diffs_; }
+
+ // Report that a field has been deleted from Message1.
+ void ReportDeleted(
+ const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+ const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+ field_path) override { ++num_diffs_; }
+
+ // Report that the value of a field has been modified.
+ void ReportModified(
+ const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+ const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+ field_path) override { ++num_diffs_; }
+
+ private:
+ int32 num_diffs_;
+};
+
// When comparing a repeated field as map, MultipleFieldMapKeyComparator can
// be used to specify multiple fields as key for key comparison.
// Two elements of a repeated field will be regarded as having the same key
@@ -144,6 +176,27 @@
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
};
+// Preserve the order when treating repeated field as SMART_LIST. The current
+// implementation is to find the longest matching sequence from the first
+// element. The optimal solution requires to use //util/diff/lcs.h, which is
+// not open sourced yet. Overwrite this method if you want to have that.
+// TODO(ykzhu): change to use LCS once it is open sourced.
+void MatchIndicesPostProcessorForSmartList(
+ std::vector<int>* match_list1, std::vector<int>* match_list2) {
+ int last_matched_index = -1;
+ for (int i = 0; i < match_list1->size(); ++i) {
+ if (match_list1->at(i) < 0) {
+ continue;
+ }
+ if (last_matched_index < 0 || match_list1->at(i) > last_matched_index) {
+ last_matched_index = match_list1->at(i);
+ } else {
+ match_list2->at(match_list1->at(i)) = -1;
+ match_list1->at(i) = -1;
+ }
+ }
+}
+
MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
MessageDifferencer* message_differencer)
: message_differencer_(message_differencer) {}
@@ -215,7 +268,9 @@
report_matches_(false),
report_moves_(true),
report_ignores_(true),
- output_string_(NULL) {}
+ output_string_(nullptr),
+ match_indices_for_smart_list_callback_(
+ MatchIndicesPostProcessorForSmartList) {}
MessageDifferencer::~MessageDifferencer() {
for (int i = 0; i < owned_key_comparators_.size(); ++i) {
@@ -255,36 +310,55 @@
repeated_field_comparison_ = comparison;
}
-void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+void MessageDifferencer::CheckRepeatedFieldComparisons(
+ const FieldDescriptor* field,
+ const RepeatedFieldComparison& new_comparison) {
GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
<< field->full_name();
const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
GOOGLE_CHECK(key_comparator == NULL)
- << "Cannot treat this repeated field as both Map and Set for"
+ << "Cannot treat this repeated field as both MAP and "
+ << new_comparison
+ << " for"
<< " comparison. Field name is: " << field->full_name();
- GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
- << "Cannot treat the same field as both SET and LIST. Field name is: "
+ GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+ repeated_field_comparisons_.end() ||
+ repeated_field_comparisons_[field] == new_comparison)
+ << "Cannot treat the same field as both "
+ << repeated_field_comparisons_[field]
+ << " and "
+ << new_comparison
+ <<". Field name is: "
<< field->full_name();
- set_fields_.insert(field);
+}
+
+void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+ CheckRepeatedFieldComparisons(field, AS_SET);
+ repeated_field_comparisons_[field] = AS_SET;
+}
+
+void MessageDifferencer::TreatAsSmartSet(const FieldDescriptor* field) {
+ CheckRepeatedFieldComparisons(field, AS_SMART_SET);
+ repeated_field_comparisons_[field] = AS_SMART_SET;
+}
+
+void MessageDifferencer::SetMatchIndicesForSmartListCallback(
+ std::function<void(std::vector<int>*, std::vector<int>*)> callback) {
+ match_indices_for_smart_list_callback_ = callback;
}
void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
- GOOGLE_CHECK(key_comparator == NULL)
- << "Cannot treat this repeated field as both Map and Set for"
- << " comparison. Field name is: " << field->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat the same field as both SET and LIST. Field name is: "
- << field->full_name();
- list_fields_.insert(field);
+ CheckRepeatedFieldComparisons(field, AS_LIST);
+ repeated_field_comparisons_[field] = AS_LIST;
+}
+
+void MessageDifferencer::TreatAsSmartList(const FieldDescriptor* field) {
+ CheckRepeatedFieldComparisons(field, AS_SMART_LIST);
+ repeated_field_comparisons_[field] = AS_SMART_LIST;
}
void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
const FieldDescriptor* key) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
<< "Field has to be message type. Field name is: "
<< field->full_name();
@@ -292,12 +366,12 @@
<< key->full_name()
<< " must be a direct subfield within the repeated field "
<< field->full_name() << ", not " << key->containing_type()->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
- GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
- << "Cannot treat this repeated field as both Map and List for "
- << "comparison.";
+ GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+ repeated_field_comparisons_.end())
+ << "Cannot treat the same field as both "
+ << repeated_field_comparisons_[field]
+ << " and MAP. Field name is: "
+ << field->full_name();
MapKeyComparator* key_comparator =
new MultipleFieldsMapKeyComparator(this, key);
owned_key_comparators_.push_back(key_comparator);
@@ -343,9 +417,12 @@
}
}
}
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
+ GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+ repeated_field_comparisons_.end())
+ << "Cannot treat the same field as both "
+ << repeated_field_comparisons_[field]
+ << " and MAP. Field name is: "
+ << field->full_name();
MapKeyComparator* key_comparator =
new MultipleFieldsMapKeyComparator(this, key_field_paths);
owned_key_comparators_.push_back(key_comparator);
@@ -357,9 +434,12 @@
const MapKeyComparator* key_comparator) {
GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
<< field->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
+ GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+ repeated_field_comparisons_.end())
+ << "Cannot treat the same field as both "
+ << repeated_field_comparisons_[field]
+ << " and MAP. Field name is: "
+ << field->full_name();
map_field_key_comparator_[field] = key_comparator;
}
@@ -795,7 +875,7 @@
const FieldDescriptor* repeated_field,
const MapKeyComparator* key_comparator, const Message* message1,
const Message* message2, const std::vector<SpecificField>& parent_fields,
- int index1, int index2) {
+ Reporter* reporter, int index1, int index2) {
std::vector<SpecificField> current_parent_fields(parent_fields);
if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
return CompareFieldValueUsingParentFields(
@@ -806,7 +886,7 @@
// following code.
Reporter* backup_reporter = reporter_;
string* output_string = output_string_;
- reporter_ = NULL;
+ reporter_ = reporter;
output_string_ = NULL;
bool match;
@@ -876,10 +956,38 @@
// At this point, we have already matched pairs of fields (with the reporting
// to be done later). Now to check if the paired elements are different.
+ int next_unmatched_index = 0;
for (int i = 0; i < count1; i++) {
- if (match_list1[i] == -1) continue;
+ if (match_list1[i] == -1) {
+ if (IsTreatedAsSmartList(repeated_field)) {
+ if (reporter_ == nullptr) return false;
+ specific_field.index = i;
+ parent_fields->push_back(specific_field);
+ reporter_->ReportDeleted(message1, message2, *parent_fields);
+ parent_fields->pop_back();
+ fieldDifferent = true;
+ // Use -2 to mark this element has been reported.
+ match_list1[i] = -2;
+ }
+ continue;
+ }
+ if (IsTreatedAsSmartList(repeated_field)) {
+ for (int j = next_unmatched_index; j < match_list1[i]; ++j) {
+ GOOGLE_CHECK_LE(0, j);
+ if (reporter_ == nullptr) return false;
+ specific_field.index = j;
+ specific_field.new_index = j;
+ parent_fields->push_back(specific_field);
+ reporter_->ReportAdded(message1, message2, *parent_fields);
+ parent_fields->pop_back();
+ fieldDifferent = true;
+ // Use -2 to mark this element has been reported.
+ match_list2[j] = -2;
+ }
+ }
specific_field.index = i;
specific_field.new_index = match_list1[i];
+ next_unmatched_index = match_list1[i] + 1;
const bool result = CompareFieldValueUsingParentFields(
message1, message2, repeated_field, i, specific_field.new_index,
@@ -996,9 +1104,29 @@
bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
if (!field->is_repeated()) return false;
- if (repeated_field_comparison_ == AS_SET)
- return list_fields_.find(field) == list_fields_.end();
- return (set_fields_.find(field) != set_fields_.end());
+ if (repeated_field_comparisons_.find(field) !=
+ repeated_field_comparisons_.end()) {
+ return repeated_field_comparisons_[field] == AS_SET;
+ }
+ return repeated_field_comparison_ == AS_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartSet(const FieldDescriptor* field) {
+ if (!field->is_repeated()) return false;
+ if (repeated_field_comparisons_.find(field) !=
+ repeated_field_comparisons_.end()) {
+ return repeated_field_comparisons_[field] == AS_SMART_SET;
+ }
+ return repeated_field_comparison_ == AS_SMART_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartList(const FieldDescriptor* field) {
+ if (!field->is_repeated()) return false;
+ if (repeated_field_comparisons_.find(field) !=
+ repeated_field_comparisons_.end()) {
+ return repeated_field_comparisons_[field] == AS_SMART_LIST;
+ }
+ return repeated_field_comparison_ == AS_SMART_LIST;
}
bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
@@ -1443,10 +1571,18 @@
// before returning.
Reporter* reporter = reporter_;
reporter_ = NULL;
+ NumDiffsReporter num_diffs_reporter;
+ std::vector<int32> num_diffs_list1;
+ if (IsTreatedAsSmartSet(repeated_field)) {
+ num_diffs_list1.assign(count1, kint32max);
+ }
bool success = true;
// Find potential match if this is a special repeated field.
- if (key_comparator != NULL || IsTreatedAsSet(repeated_field)) {
+ if (key_comparator != nullptr ||
+ IsTreatedAsSet(repeated_field) ||
+ IsTreatedAsSmartSet(repeated_field) ||
+ IsTreatedAsSmartList(repeated_field)) {
if (scope_ == PARTIAL) {
// When partial matching is enabled, Compare(a, b) && Compare(a, c)
// doesn't necessarily imply Compare(b, c). Therefore a naive greedy
@@ -1456,7 +1592,7 @@
::google::protobuf::NewPermanentCallback(
this, &MessageDifferencer::IsMatch,
repeated_field, key_comparator,
- &message1, &message2, parent_fields);
+ &message1, &message2, parent_fields, nullptr);
MaximumMatcher matcher(count1, count2, callback, match_list1,
match_list2);
// If diff info is not needed, we should end the matching process as
@@ -1469,11 +1605,13 @@
int start_offset = 0;
// If the two repeated fields are treated as sets, optimize for the case
// where both start with same items stored in the same order.
- if (IsTreatedAsSet(repeated_field)) {
+ if (IsTreatedAsSet(repeated_field) ||
+ IsTreatedAsSmartSet(repeated_field) ||
+ IsTreatedAsSmartList(repeated_field)) {
start_offset = std::min(count1, count2);
for (int i = 0; i < count1 && i < count2; i++) {
if (IsMatch(repeated_field, key_comparator, &message1, &message2,
- parent_fields, i, i)) {
+ parent_fields, nullptr, i, i)) {
match_list1->at(i) = i;
match_list2->at(i) = i;
} else {
@@ -1487,15 +1625,45 @@
bool match = false;
for (int j = start_offset; j < count2; j++) {
- if (match_list2->at(j) != -1) continue;
+ if (match_list2->at(j) != -1) {
+ if (!IsTreatedAsSmartSet(repeated_field) ||
+ num_diffs_list1[i] == 0) {
+ continue;
+ }
+ }
- match = IsMatch(repeated_field, key_comparator,
- &message1, &message2, parent_fields, i, j);
+ if (IsTreatedAsSmartSet(repeated_field)) {
+ num_diffs_reporter.Reset();
+ match = IsMatch(repeated_field, key_comparator,
+ &message1, &message2, parent_fields,
+ &num_diffs_reporter, i, j);
+ } else {
+ match = IsMatch(repeated_field, key_comparator,
+ &message1, &message2, parent_fields,
+ nullptr, i, j);
+ }
+
+ if (IsTreatedAsSmartSet(repeated_field)) {
+ if (match) {
+ num_diffs_list1[i] = 0;
+ } else if (repeated_field->cpp_type() ==
+ FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Replace with the one with fewer diffs.
+ const int32 num_diffs = num_diffs_reporter.GetNumDiffs();
+ if (num_diffs < num_diffs_list1[i]) {
+ num_diffs_list1[i] = num_diffs;
+ match = true;
+ }
+ }
+ }
if (match) {
match_list1->at(i) = j;
match_list2->at(j) = i;
- break;
+ if (!IsTreatedAsSmartSet(repeated_field)
+ || num_diffs_list1[i] == 0) {
+ break;
+ }
}
}
if (!match && reporter == NULL) return false;
@@ -1510,6 +1678,10 @@
}
}
+ if (IsTreatedAsSmartList(repeated_field)) {
+ match_indices_for_smart_list_callback_(match_list1, match_list2);
+ }
+
reporter_ = reporter;
return success;
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 9419267..96d0f0c 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -42,6 +42,7 @@
#ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
#define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+#include <functional>
#include <map>
#include <set>
#include <string>
@@ -69,6 +70,7 @@
class DefaultFieldComparator;
class FieldContext; // declared below MessageDifferencer
+
// A basic differencer that can be used to determine
// the differences between two specified Protocol Messages. If any differences
// are found, the Compare method will return false, and any differencer reporter
@@ -368,13 +370,18 @@
};
enum RepeatedFieldComparison {
- AS_LIST, // Repeated fields are compared in order. Differing values at
- // the same index are reported using ReportModified(). If the
- // repeated fields have different numbers of elements, the
- // unpaired elements are reported using ReportAdded() or
- // ReportDeleted().
- AS_SET, // Treat all the repeated fields as sets.
- // See TreatAsSet(), as below.
+ AS_LIST, // Repeated fields are compared in order. Differing values at
+ // the same index are reported using ReportModified(). If the
+ // repeated fields have different numbers of elements, the
+ // unpaired elements are reported using ReportAdded() or
+ // ReportDeleted().
+ AS_SET, // Treat all the repeated fields as sets.
+ // See TreatAsSet(), as below.
+ AS_SMART_LIST, // Similar to AS_SET, but preserve the order and find the
+ // longest matching sequence from the first matching
+ // element. To use an optimal solution, call
+ // SetMatchIndicesForSmartListCallback() to pass it in.
+ AS_SMART_SET, // Similar to AS_SET, but match elements with fewest diffs.
};
// The elements of the given repeated field will be treated as a set for
@@ -406,6 +413,7 @@
//
// REQUIRES: field->is_repeated() and field not registered with TreatAsList
void TreatAsSet(const FieldDescriptor* field);
+ void TreatAsSmartSet(const FieldDescriptor* field);
// The elements of the given repeated field will be treated as a list for
// diffing purposes, so different orderings of the same elements will NOT be
@@ -413,6 +421,8 @@
//
// REQUIRED: field->is_repeated() and field not registered with TreatAsSet
void TreatAsList(const FieldDescriptor* field);
+ // Note that the complexity is similar to treating as SET.
+ void TreatAsSmartList(const FieldDescriptor* field);
// The elements of the given repeated field will be treated as a map for
// diffing purposes, with |key| being the map key. Thus, elements with the
@@ -778,11 +788,20 @@
const MapKeyComparator* key_comparator,
const Message* message1, const Message* message2,
const std::vector<SpecificField>& parent_fields,
- int index1, int index2);
+ Reporter* reporter, int index1, int index2);
// Returns true when this repeated field has been configured to be treated
- // as a set.
+ // as a Set / SmartSet / SmartList.
bool IsTreatedAsSet(const FieldDescriptor* field);
+ bool IsTreatedAsSmartSet(const FieldDescriptor* field);
+
+ bool IsTreatedAsSmartList(const FieldDescriptor* field);
+ // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList
+ // by default to find the longest matching sequence from the first matching
+ // element. The callback takes two vectors showing the matching indices from
+ // the other vector, where -1 means an unmatch.
+ void SetMatchIndicesForSmartListCallback(
+ std::function<void(std::vector<int>*, std::vector<int>*)> callback);
// Returns true when this repeated field is to be compared as a subset, ie.
// has been configured to be treated as a set or map and scope is set to
@@ -830,6 +849,12 @@
// Checks if index is equal to new_index in all the specific fields.
static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields);
+ // CHECKs that the given repeated field can be compared according to
+ // new_comparison.
+ void CheckRepeatedFieldComparisons(
+ const FieldDescriptor* field,
+ const RepeatedFieldComparison& new_comparison);
+
// Defines a map between field descriptors and their MapKeyComparators.
// Used for repeated fields when they are configured as TreatAsMap.
typedef std::map<const FieldDescriptor*,
@@ -838,6 +863,7 @@
// Defines a set to store field descriptors. Used for repeated fields when
// they are configured as TreatAsSet.
typedef std::set<const FieldDescriptor*> FieldSet;
+ typedef std::map<const FieldDescriptor*, RepeatedFieldComparison> FieldMap;
Reporter* reporter_;
DefaultFieldComparator default_field_comparator_;
@@ -846,8 +872,7 @@
Scope scope_;
RepeatedFieldComparison repeated_field_comparison_;
- FieldSet set_fields_;
- FieldSet list_fields_;
+ FieldMap repeated_field_comparisons_;
// Keeps track of MapKeyComparators that are created within
// MessageDifferencer. These MapKeyComparators should be deleted
// before MessageDifferencer is destroyed.
@@ -867,6 +892,10 @@
std::string* output_string_;
+ // Callback to post-process the matched indices to support SMART_LIST.
+ std::function<void(std::vector<int>*,
+ std::vector<int>*)> match_indices_for_smart_list_callback_;
+
std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer);
};
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 848290b..24c05c6 100644
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -1049,6 +1049,132 @@
EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
}
+TEST(MessageDifferencerTest, RepeatedFieldSmartListTest) {
+ // Create the testing protos
+ protobuf_unittest::TestDiffMessage msg1;
+ protobuf_unittest::TestDiffMessage msg2;
+
+ msg1.add_rv(1);
+ msg1.add_rv(2);
+ msg1.add_rv(3);
+ msg1.add_rv(9);
+ msg1.add_rv(4);
+ msg1.add_rv(5);
+ msg1.add_rv(7);
+ msg1.add_rv(2);
+ msg2.add_rv(9);
+ msg2.add_rv(0);
+ msg2.add_rv(2);
+ msg2.add_rv(7);
+ msg2.add_rv(3);
+ msg2.add_rv(4);
+ msg2.add_rv(5);
+ msg2.add_rv(6);
+ msg2.add_rv(2);
+ // Compare
+ // a: 1, 2, 3, 9, 4, 5, 7, 2
+ // b: 9, 0, 2, 7, 3, 4, 5, 6, 2
+ string diff_report;
+ util::MessageDifferencer differencer;
+ differencer.ReportDifferencesToString(&diff_report);
+ differencer.set_repeated_field_comparison(
+ util::MessageDifferencer::AS_SMART_LIST);
+ EXPECT_FALSE(differencer.Compare(msg1, msg2));
+ EXPECT_EQ("deleted: rv[0]: 1\n"
+ "added: rv[0]: 9\n"
+ "added: rv[1]: 0\n"
+ "moved: rv[1] -> rv[2] : 2\n"
+ "added: rv[3]: 7\n"
+ "moved: rv[2] -> rv[4] : 3\n"
+ "deleted: rv[3]: 9\n"
+ "moved: rv[4] -> rv[5] : 4\n"
+ "moved: rv[5] -> rv[6] : 5\n"
+ "deleted: rv[6]: 7\n"
+ "added: rv[7]: 6\n"
+ "moved: rv[7] -> rv[8] : 2\n", diff_report);
+
+ // Compare two sub messages
+ // a: 1, 2, 3, 4, 5
+ // b: 2, 6, 4,
+ msg1.Clear();
+ msg2.Clear();
+ msg1.add_rm()->set_a(1);
+ msg1.add_rm()->set_a(2);
+ msg1.add_rm()->set_a(3);
+ msg1.add_rm()->set_a(4);
+ msg1.add_rm()->set_a(5);
+ msg2.add_rm()->set_a(2);
+ msg2.add_rm()->set_a(6);
+ msg2.add_rm()->set_a(4);
+ differencer.ReportDifferencesToString(&diff_report);
+ differencer.set_repeated_field_comparison(
+ util::MessageDifferencer::AS_SMART_LIST);
+ EXPECT_FALSE(differencer.Compare(msg1, msg2));
+ EXPECT_EQ("deleted: rm[0]: { a: 1 }\n"
+ "moved: rm[1] -> rm[0] : { a: 2 }\n"
+ "deleted: rm[2]: { a: 3 }\n"
+ "added: rm[1]: { a: 6 }\n"
+ "moved: rm[3] -> rm[2] : { a: 4 }\n"
+ "deleted: rm[4]: { a: 5 }\n", diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest) {
+ // Create the testing protos
+ protobuf_unittest::TestDiffMessage msg1;
+ protobuf_unittest::TestDiffMessage msg2;
+ protobuf_unittest::TestField elem1_1, elem2_1, elem3_1;
+ protobuf_unittest::TestField elem1_2, elem2_2, elem3_2;
+
+ // Only one field is different for each pair of elememts
+ elem1_1.set_a(1); elem1_2.set_a(0);
+ elem1_1.set_b(1); elem1_2.set_b(1);
+ elem1_1.set_c(1); elem1_2.set_c(1);
+ elem2_1.set_a(2); elem2_2.set_a(2);
+ elem2_1.set_b(2); elem2_2.set_b(0);
+ elem2_1.set_c(2); elem2_2.set_c(2);
+ elem3_1.set_a(3); elem3_2.set_a(3);
+ elem3_1.set_b(3); elem3_2.set_b(0);
+ elem3_1.set_c(3); elem3_2.set_c(3);
+
+ *msg1.add_rm() = elem1_1;
+ *msg1.add_rm() = elem2_1;
+ *msg1.add_rm() = elem3_1;
+ // Change the order of those elements for the second message.
+ *msg2.add_rm() = elem3_2;
+ *msg2.add_rm() = elem1_2;
+ *msg2.add_rm() = elem2_2;
+
+ string diff_report;
+ util::MessageDifferencer differencer;
+ differencer.ReportDifferencesToString(&diff_report);
+ differencer.set_repeated_field_comparison(
+ util::MessageDifferencer::AS_SMART_SET);
+ EXPECT_FALSE(differencer.Compare(msg1, msg2));
+ EXPECT_EQ("modified: rm[0].a -> rm[1].a: 1 -> 0\n"
+ "modified: rm[1].b -> rm[2].b: 2 -> 0\n"
+ "modified: rm[2].b -> rm[0].b: 3 -> 0\n", diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSet_NonMessageTypeTest) {
+ // Create the testing protos
+ protobuf_unittest::TestDiffMessage msg1;
+ protobuf_unittest::TestDiffMessage msg2;
+
+ // Create 3 elements, but in different order.
+ msg1.add_rw("b"); msg2.add_rw("a");
+ msg1.add_rw("x"); msg2.add_rw("x");
+ msg1.add_rw("a"); msg2.add_rw("b");
+
+ string diff_report;
+ util::MessageDifferencer differencer;
+ differencer.ReportDifferencesToString(&diff_report);
+ differencer.set_repeated_field_comparison(
+ util::MessageDifferencer::AS_SMART_SET);
+ EXPECT_TRUE(differencer.Compare(msg1, msg2));
+ EXPECT_EQ("moved: rw[0] -> rw[2] : \"b\"\n"
+ "moved: rw[2] -> rw[0] : \"a\"\n", diff_report);
+}
+
TEST(MessageDifferencerTest, RepeatedFieldSetTest_SetOfSet) {
// Create the testing protos
protobuf_unittest::TestDiffMessage msg1;
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index 3a3eba4..f40ce94 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -44,12 +44,21 @@
namespace protobuf {
namespace util {
namespace {
+using google::protobuf::Any;
using google::protobuf::BoolValue;
+using google::protobuf::BytesValue;
+using google::protobuf::DoubleValue;
using google::protobuf::Enum;
using google::protobuf::EnumValue;
using google::protobuf::Field;
+using google::protobuf::FloatValue;
+using google::protobuf::Int32Value;
+using google::protobuf::Int64Value;
using google::protobuf::Option;
+using google::protobuf::StringValue;
using google::protobuf::Type;
+using google::protobuf::UInt32Value;
+using google::protobuf::UInt64Value;
using util::Status;
using util::error::INVALID_ARGUMENT;
@@ -70,7 +79,8 @@
const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
if (descriptor == NULL) {
- return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
+ return Status(util::error::NOT_FOUND,
+ "Invalid type URL, unknown type: " + type_name);
}
ConvertDescriptor(descriptor, type);
return Status();
@@ -85,7 +95,8 @@
const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
if (descriptor == NULL) {
- return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
+ return Status(util::error::NOT_FOUND,
+ "Invalid type URL, unknown type: " + type_name);
}
ConvertEnumDescriptor(descriptor, enum_type);
return Status();
@@ -107,15 +118,104 @@
void ConvertMessageOptions(const MessageOptions& options,
RepeatedPtrField<Option>* output) {
- if (options.map_entry()) {
- Option* option = output->Add();
- option->set_name("map_entry");
- BoolValue value;
- value.set_value(true);
- option->mutable_value()->PackFrom(value);
+ const Reflection* reflection = options.GetReflection();
+ std::vector<const FieldDescriptor*> fields;
+ reflection->ListFields(options, &fields);
+ for (const FieldDescriptor* field : fields) {
+ if (field->is_repeated()) {
+ const int size = reflection->FieldSize(options, field);
+ for (int i = 0; i < size; i++) {
+ ConvertMessageOption(reflection, options, field, i, output->Add());
+ }
+ } else {
+ ConvertMessageOption(reflection, options, field, -1, output->Add());
+ }
}
+ }
- // TODO(xiaofeng): Set other "options"?
+ static void ConvertMessageOption(const Reflection* reflection,
+ const MessageOptions& options,
+ const FieldDescriptor* field, int index,
+ Option* out) {
+ out->set_name(field->is_extension() ? field->full_name() : field->name());
+ Any* value = out->mutable_value();
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ value->PackFrom(
+ field->is_repeated()
+ ? reflection->GetRepeatedMessage(options, field, index)
+ : reflection->GetMessage(options, field));
+ return;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ value->PackFrom(WrapValue<DoubleValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedDouble(options, field, index)
+ : reflection->GetDouble(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ value->PackFrom(WrapValue<FloatValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedFloat(options, field, index)
+ : reflection->GetFloat(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_INT64:
+ value->PackFrom(WrapValue<Int64Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedInt64(options, field, index)
+ : reflection->GetInt64(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ value->PackFrom(WrapValue<UInt64Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedUInt64(options, field, index)
+ : reflection->GetUInt64(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_INT32:
+ value->PackFrom(WrapValue<Int32Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedInt32(options, field, index)
+ : reflection->GetInt32(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ value->PackFrom(WrapValue<UInt32Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedUInt32(options, field, index)
+ : reflection->GetUInt32(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ value->PackFrom(WrapValue<BoolValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedBool(options, field, index)
+ : reflection->GetBool(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_STRING: {
+ const string& val =
+ field->is_repeated()
+ ? reflection->GetRepeatedString(options, field, index)
+ : reflection->GetString(options, field);
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ value->PackFrom(WrapValue<StringValue>(val));
+ } else {
+ value->PackFrom(WrapValue<BytesValue>(val));
+ }
+ return;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ const EnumValueDescriptor* val =
+ field->is_repeated()
+ ? reflection->GetRepeatedEnum(options, field, index)
+ : reflection->GetEnum(options, field);
+ value->PackFrom(WrapValue<Int32Value>(val->number()));
+ return;
+ }
+ }
+ }
+
+ template <typename WrapperT, typename T>
+ static WrapperT WrapValue(T value) {
+ WrapperT wrapper;
+ wrapper.set_value(value);
+ return wrapper;
}
void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
@@ -181,7 +281,7 @@
Status ParseTypeUrl(const string& type_url, string* type_name) {
if (type_url.substr(0, url_prefix_.size() + 1) != url_prefix_ + "/") {
return Status(
- INVALID_ARGUMENT,
+ util::error::INVALID_ARGUMENT,
StrCat("Invalid type URL, type URLs must be of the form '",
url_prefix_, "/<typename>', got: ", type_url));
}
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index 9dea17a..fa06037 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -40,6 +40,7 @@
#include <google/protobuf/map_unittest.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
#include <google/protobuf/util/json_format_proto3.pb.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/testing/googletest.h>
@@ -49,11 +50,12 @@
namespace protobuf {
namespace util {
namespace {
-using google::protobuf::Type;
+using google::protobuf::BoolValue;
using google::protobuf::Enum;
using google::protobuf::Field;
+using google::protobuf::Int32Value;
using google::protobuf::Option;
-using google::protobuf::BoolValue;
+using google::protobuf::Type;
static const char kUrlPrefix[] = "type.googleapis.com";
@@ -127,12 +129,21 @@
bool HasBoolOption(const RepeatedPtrField<Option>& options,
const string& name, bool value) {
- for (int i = 0; i < options.size(); ++i) {
- const Option& option = options.Get(i);
+ return HasOption<BoolValue>(options, name, value);
+ }
+
+ bool HasInt32Option(const RepeatedPtrField<Option>& options,
+ const string& name, int32 value) {
+ return HasOption<Int32Value>(options, name, value);
+ }
+
+ template <typename WrapperT, typename T>
+ bool HasOption(const RepeatedPtrField<Option>& options, const string& name,
+ T value) {
+ for (const Option& option : options) {
if (option.name() == name) {
- BoolValue bool_value;
- if (option.value().UnpackTo(&bool_value) &&
- bool_value.value() == value) {
+ WrapperT wrapper;
+ if (option.value().UnpackTo(&wrapper) && wrapper.value() == value) {
return true;
}
}
@@ -327,6 +338,18 @@
EXPECT_TRUE(HasBoolOption(type.options(), "map_entry", true));
}
+TEST_F(DescriptorPoolTypeResolverTest, TestCustomOptions) {
+ Type type;
+ ASSERT_TRUE(
+ resolver_
+ ->ResolveMessageType(
+ GetTypeUrl<protobuf_unittest::TestMessageWithCustomOptions>(),
+ &type)
+ .ok());
+ EXPECT_TRUE(
+ HasInt32Option(type.options(), "protobuf_unittest.message_opt1", -56));
+}
+
TEST_F(DescriptorPoolTypeResolverTest, TestEnum) {
Enum type;
ASSERT_TRUE(resolver_->ResolveEnumType(
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 60cadae..f576875 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -768,7 +768,7 @@
public:
explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
: unknown_fields_(unknown_fields) {}
- virtual ~CodedOutputStreamFieldSkipper() {}
+ ~CodedOutputStreamFieldSkipper() override {}
// implements FieldSkipper -----------------------------------------
bool SkipField(io::CodedInputStream* input, uint32 tag) override;
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index babdcc6..114e883 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -49,6 +49,7 @@
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/port_def.inc>
@@ -1148,10 +1149,6 @@
return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
}
-bool StartsWith(const string& s, const string& prefix) {
- return s.substr(0, prefix.length()) == prefix;
-}
-
class Utf8ValidationTest : public ::testing::Test {
protected:
Utf8ValidationTest() {}
@@ -1172,11 +1169,12 @@
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_TRUE(StartsWith(errors[0],
- "String field 'protobuf_unittest.OneString.data' "
- "contains invalid UTF-8 data when "
- "serializing a protocol buffer. Use the "
- "'bytes' type if you intend to send raw bytes."));
+ EXPECT_TRUE(
+ HasPrefixString(errors[0],
+ "String field 'protobuf_unittest.OneString.data' "
+ "contains invalid UTF-8 data when "
+ "serializing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
#else
ASSERT_EQ(0, errors.size());
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
@@ -1196,11 +1194,12 @@
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_TRUE(StartsWith(errors[0],
- "String field 'protobuf_unittest.OneString.data' "
- "contains invalid UTF-8 data when "
- "parsing a protocol buffer. Use the "
- "'bytes' type if you intend to send raw bytes."));
+ EXPECT_TRUE(
+ HasPrefixString(errors[0],
+ "String field 'protobuf_unittest.OneString.data' "
+ "contains invalid UTF-8 data when "
+ "parsing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
#else
ASSERT_EQ(0, errors.size());
@@ -1299,10 +1298,11 @@
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
ASSERT_EQ(1, errors.size());
- EXPECT_TRUE(StartsWith(errors[0],
- "String field contains invalid UTF-8 data when "
- "serializing a protocol buffer. Use the "
- "'bytes' type if you intend to send raw bytes."));
+ EXPECT_TRUE(
+ HasPrefixString(errors[0],
+ "String field contains invalid UTF-8 data when "
+ "serializing a protocol buffer. Use the "
+ "'bytes' type if you intend to send raw bytes."));
#else
ASSERT_EQ(0, errors.size());
#endif
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 3d7e7cb..f3a92a4 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -284,8 +284,7 @@
file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, 9, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto, file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
};
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
- false, InitDefaults_google_2fprotobuf_2fwrappers_2eproto,
+const char descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto[] =
"\n\036google/protobuf/wrappers.proto\022\017google"
".protobuf\"\034\n\013DoubleValue\022\r\n\005value\030\001 \001(\001\""
"\033\n\nFloatValue\022\r\n\005value\030\001 \001(\002\"\033\n\nInt64Val"
@@ -298,7 +297,10 @@
"b.com/golang/protobuf/ptypes/wrappers\370\001\001"
"\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb"
"\006proto3"
-,
+ ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+ false, InitDefaults_google_2fprotobuf_2fwrappers_2eproto,
+ descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
"google/protobuf/wrappers.proto", &assign_descriptors_table_google_2fprotobuf_2fwrappers_2eproto, 447,
};
@@ -390,10 +392,10 @@
auto msg = static_cast<DoubleValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -409,13 +411,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -426,7 +428,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -687,10 +689,10 @@
auto msg = static_cast<FloatValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -706,13 +708,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -723,7 +725,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -984,10 +986,10 @@
auto msg = static_cast<Int64Value*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1004,13 +1006,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1021,7 +1023,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1284,10 +1286,10 @@
auto msg = static_cast<UInt64Value*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1304,13 +1306,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1321,7 +1323,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1584,10 +1586,10 @@
auto msg = static_cast<Int32Value*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1604,13 +1606,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1621,7 +1623,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1884,10 +1886,10 @@
auto msg = static_cast<UInt32Value*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -1904,13 +1906,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -1921,7 +1923,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2184,10 +2186,10 @@
auto msg = static_cast<BoolValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -2204,13 +2206,13 @@
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2221,7 +2223,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2489,10 +2491,10 @@
auto msg = static_cast<StringValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -2502,26 +2504,29 @@
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.StringValue.value");
- parser_till_end = ::google::protobuf::internal::StringParserUTF8;
- ::std::string* str = msg->mutable_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- auto newend = ptr + size;
- if (size) ptr = parser_till_end(ptr, newend, object, ctx);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+ auto str = msg->mutable_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+ ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2532,7 +2537,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2816,10 +2821,10 @@
auto msg = static_cast<BytesValue*>(object);
::google::protobuf::uint32 size; (void)size;
int depth; (void)depth;
+ ::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin;
while (ptr < end) {
- ::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) {
@@ -2828,25 +2833,29 @@
if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- parser_till_end = ::google::protobuf::internal::StringParser;
- ::std::string* str = msg->mutable_value();
- str->clear();
- object = str;
- if (size > end - ptr) goto len_delim_till_end;
- str->append(ptr, size);
+ auto str = msg->mutable_value();
+ if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+ object = str;
+ str->clear();
+ str->reserve(size);
+ parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+ goto len_delim_till_end;
+ }
+ GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+ ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break;
}
default: {
handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) {
- bool ok = ctx->ValidEndGroup(tag);
- GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+ ctx->EndGroup(tag);
return ptr;
}
auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first;
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr;
}
} // switch
@@ -2857,7 +2866,7 @@
{parser_till_end, object}, size);
group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end);
- ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr;
}
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 5b1d70a..7dbe49e 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -157,7 +157,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const DoubleValue& from);
void MergeFrom(const DoubleValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -283,7 +283,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const FloatValue& from);
void MergeFrom(const FloatValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -409,7 +409,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Int64Value& from);
void MergeFrom(const Int64Value& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -535,7 +535,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const UInt64Value& from);
void MergeFrom(const UInt64Value& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -661,7 +661,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Int32Value& from);
void MergeFrom(const Int32Value& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -787,7 +787,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const UInt32Value& from);
void MergeFrom(const UInt32Value& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -913,7 +913,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const BoolValue& from);
void MergeFrom(const BoolValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1039,7 +1039,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const StringValue& from);
void MergeFrom(const StringValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
@@ -1182,7 +1182,7 @@
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const BytesValue& from);
void MergeFrom(const BytesValue& from);
- void Clear() final;
+ PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;