aboutsummaryrefslogtreecommitdiffhomepage
path: root/java/src/main
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-01-22 01:27:00 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-01-22 01:27:00 +0000
commit2d6daa72ab5832bf4cab38df0d911f32df547021 (patch)
tree5f9304a6ff2c7c0cb7ed62eead92bf05411666f8 /java/src/main
parent87e64e1ceeff224043078e7e31fe0b1a119c8b1a (diff)
Push out changes from internal codebase.
All Languages * Repeated fields of primitive types (types other that string, group, and nested messages) may now use the option [packed = true] to get a more efficient encoding. In the new encoding, the entire list is written as a single byte blob using the "length-delimited" wire type. Within this blob, the individual values are encoded the same way they would be normally except without a tag before each value (thus, they are tightly "packed"). C++ * UnknownFieldSet now supports STL-like iteration. * Message interface has method ParseFromBoundedZeroCopyStream() which parses a limited number of bytes from an input stream rather than parsing until EOF. Java * Fixed bug where Message.mergeFrom(Message) failed to merge extensions. * Message interface has new method toBuilder() which is equivalent to newBuilderForType().mergeFrom(this). * All enums now implement the ProtocolMessageEnum interface. * Setting a field to null now throws NullPointerException. * Fixed tendency for TextFormat's parsing to overflow the stack when parsing large string values. The underlying problem is with Java's regex implementation (which unfortunately uses recursive backtracking rather than building an NFA). Worked around by making use of possesive quantifiers. Python * Updated RPC interfaces to allow for blocking operation. A client may now pass None for a callback when making an RPC, in which case the call will block until the response is received, and the response object will be returned directly to the caller. This interface change cannot be used in practice until RPC implementations are updated to implement it.
Diffstat (limited to 'java/src/main')
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessage.java43
-rw-r--r--java/src/main/java/com/google/protobuf/CodedInputStream.java15
-rw-r--r--java/src/main/java/com/google/protobuf/CodedOutputStream.java507
-rw-r--r--java/src/main/java/com/google/protobuf/Descriptors.java13
-rw-r--r--java/src/main/java/com/google/protobuf/DynamicMessage.java5
-rw-r--r--java/src/main/java/com/google/protobuf/FieldSet.java154
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessage.java102
-rw-r--r--java/src/main/java/com/google/protobuf/Message.java6
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java12
-rw-r--r--java/src/main/java/com/google/protobuf/WireFormat.java10
10 files changed, 653 insertions, 214 deletions
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
index 2f61859d..24c32a47 100644
--- a/java/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -86,8 +86,25 @@ public abstract class AbstractMessage implements Message {
for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
- for (Object element : (List) entry.getValue()) {
- output.writeField(field.getType(), field.getNumber(), element);
+ List valueList = (List) entry.getValue();
+ if (field.getOptions().getPacked()) {
+
+ output.writeTag(field.getNumber(),
+ WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ int dataSize = 0;
+ for (Object element : valueList) {
+ dataSize += CodedOutputStream.computeFieldSizeNoTag(
+ field.getType(), element);
+ }
+ output.writeRawVarint32(dataSize);
+
+ for (Object element : valueList) {
+ output.writeFieldNoTag(field.getType(), element);
+ }
+ } else {
+ for (Object element : valueList) {
+ output.writeField(field.getType(), field.getNumber(), element);
+ }
}
} else {
output.writeField(field.getType(), field.getNumber(), entry.getValue());
@@ -145,9 +162,21 @@ public abstract class AbstractMessage implements Message {
for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
- for (Object element : (List) entry.getValue()) {
- size += CodedOutputStream.computeFieldSize(
- field.getType(), field.getNumber(), element);
+ List valueList = (List) entry.getValue();
+ if (field.getOptions().getPacked()) {
+ int dataSize = 0;
+ for (Object element : valueList) {
+ dataSize += CodedOutputStream.computeFieldSizeNoTag(
+ field.getType(), element);
+ }
+ size += dataSize;
+ size += CodedOutputStream.computeTagSize(field.getNumber());
+ size += CodedOutputStream.computeRawVarint32Size(dataSize);
+ } else {
+ for (Object element : valueList) {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), element);
+ }
}
} else {
size += CodedOutputStream.computeFieldSize(
@@ -165,7 +194,7 @@ public abstract class AbstractMessage implements Message {
memoizedSize = size;
return size;
}
-
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -180,7 +209,7 @@ public abstract class AbstractMessage implements Message {
}
return getAllFields().equals(otherMessage.getAllFields());
}
-
+
@Override
public int hashCode() {
int hash = 41;
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java
index caef068b..8f277a9f 100644
--- a/java/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -193,7 +193,7 @@ public final class CodedInputStream {
/** Read a {@code string} field value from the stream. */
public String readString() throws IOException {
int size = readRawVarint32();
- if (size < bufferSize - bufferPos && size > 0) {
+ if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
String result = new String(buffer, bufferPos, size, "UTF-8");
@@ -584,6 +584,19 @@ public final class CodedInputStream {
}
/**
+ * Returns the number of bytes to be read before the current limit.
+ * If no limit is set, returns -1.
+ */
+ public int getBytesUntilLimit() {
+ if (currentLimit == Integer.MAX_VALUE) {
+ return -1;
+ }
+
+ int currentAbsolutePosition = totalBytesRetired + bufferPos;
+ return currentLimit - currentAbsolutePosition;
+ }
+
+ /**
* Called with {@code this.buffer} is empty to read more bytes from the
* input. If {@code mustSucceed} is true, refillBuffer() gurantees that
* either there will be at least one byte in the buffer when it returns
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
index d232841a..e8be8611 100644
--- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -118,71 +118,61 @@ public final class CodedOutputStream {
/** Write a {@code double} field, including tag, to the stream. */
public void writeDouble(int fieldNumber, double value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeRawLittleEndian64(Double.doubleToRawLongBits(value));
+ writeDoubleNoTag(value);
}
/** Write a {@code float} field, including tag, to the stream. */
public void writeFloat(int fieldNumber, float value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeRawLittleEndian32(Float.floatToRawIntBits(value));
+ writeFloatNoTag(value);
}
/** Write a {@code uint64} field, including tag, to the stream. */
public void writeUInt64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint64(value);
+ writeUInt64NoTag(value);
}
/** Write an {@code int64} field, including tag, to the stream. */
public void writeInt64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint64(value);
+ writeInt64NoTag(value);
}
/** Write an {@code int32} field, including tag, to the stream. */
public void writeInt32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- if (value >= 0) {
- writeRawVarint32(value);
- } else {
- // Must sign-extend.
- writeRawVarint64(value);
- }
+ writeInt32NoTag(value);
}
/** Write a {@code fixed64} field, including tag, to the stream. */
public void writeFixed64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeRawLittleEndian64(value);
+ writeFixed64NoTag(value);
}
/** Write a {@code fixed32} field, including tag, to the stream. */
public void writeFixed32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeRawLittleEndian32(value);
+ writeFixed32NoTag(value);
}
/** Write a {@code bool} field, including tag, to the stream. */
public void writeBool(int fieldNumber, boolean value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawByte(value ? 1 : 0);
+ writeBoolNoTag(value);
}
/** Write a {@code string} field, including tag, to the stream. */
public void writeString(int fieldNumber, String value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- // Unfortunately there does not appear to be any way to tell Java to encode
- // UTF-8 directly into our buffer, so we have to let it create its own byte
- // array and then copy.
- byte[] bytes = value.getBytes("UTF-8");
- writeRawVarint32(bytes.length);
- writeRawBytes(bytes);
+ writeStringNoTag(value);
}
/** Write a {@code group} field, including tag, to the stream. */
public void writeGroup(int fieldNumber, Message value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
- value.writeTo(this);
+ writeGroupNoTag(value);
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
@@ -190,29 +180,26 @@ public final class CodedOutputStream {
public void writeUnknownGroup(int fieldNumber, UnknownFieldSet value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
- value.writeTo(this);
+ writeUnknownGroupNoTag(value);
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
/** Write an embedded message field, including tag, to the stream. */
public void writeMessage(int fieldNumber, Message value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeRawVarint32(value.getSerializedSize());
- value.writeTo(this);
+ writeMessageNoTag(value);
}
/** Write a {@code bytes} field, including tag, to the stream. */
public void writeBytes(int fieldNumber, ByteString value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- byte[] bytes = value.toByteArray();
- writeRawVarint32(bytes.length);
- writeRawBytes(bytes);
+ writeBytesNoTag(value);
}
/** Write a {@code uint32} field, including tag, to the stream. */
public void writeUInt32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint32(value);
+ writeUInt32NoTag(value);
}
/**
@@ -221,31 +208,31 @@ public final class CodedOutputStream {
*/
public void writeEnum(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint32(value);
+ writeEnumNoTag(value);
}
/** Write an {@code sfixed32} field, including tag, to the stream. */
public void writeSFixed32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeRawLittleEndian32(value);
+ writeSFixed32NoTag(value);
}
/** Write an {@code sfixed64} field, including tag, to the stream. */
public void writeSFixed64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeRawLittleEndian64(value);
+ writeSFixed64NoTag(value);
}
/** Write an {@code sint32} field, including tag, to the stream. */
public void writeSInt32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint32(encodeZigZag32(value));
+ writeSInt32NoTag(value);
}
/** Write an {@code sint64} field, including tag, to the stream. */
public void writeSInt64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeRawVarint64(encodeZigZag64(value));
+ writeSInt64NoTag(value);
}
/**
@@ -283,32 +270,168 @@ public final class CodedOutputStream {
* this field.
*/
public void writeField(Descriptors.FieldDescriptor.Type type,
- int number, Object value) throws IOException {
+ int number,
+ Object value) throws IOException {
+ // Special case for groups, which need a start and end tag; other fields
+ // can just use writeTag() and writeFieldNoTag().
+ if (type == Descriptors.FieldDescriptor.Type.GROUP) {
+ writeGroup(number, (Message) value);
+ } else {
+ writeTag(number, WireFormat.getWireFormatForFieldType(type));
+ writeFieldNoTag(type, value);
+ }
+ }
+
+ /**
+ * Write a field of arbitrary type, without its tag, to the stream.
+ *
+ * @param type The field's type.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public void writeFieldNoTag(Descriptors.FieldDescriptor.Type type,
+ Object value) throws IOException {
switch (type) {
- case DOUBLE : writeDouble (number, (Double )value); break;
- case FLOAT : writeFloat (number, (Float )value); break;
- case INT64 : writeInt64 (number, (Long )value); break;
- case UINT64 : writeUInt64 (number, (Long )value); break;
- case INT32 : writeInt32 (number, (Integer )value); break;
- case FIXED64 : writeFixed64 (number, (Long )value); break;
- case FIXED32 : writeFixed32 (number, (Integer )value); break;
- case BOOL : writeBool (number, (Boolean )value); break;
- case STRING : writeString (number, (String )value); break;
- case GROUP : writeGroup (number, (Message )value); break;
- case MESSAGE : writeMessage (number, (Message )value); break;
- case BYTES : writeBytes (number, (ByteString)value); break;
- case UINT32 : writeUInt32 (number, (Integer )value); break;
- case SFIXED32: writeSFixed32(number, (Integer )value); break;
- case SFIXED64: writeSFixed64(number, (Long )value); break;
- case SINT32 : writeSInt32 (number, (Integer )value); break;
- case SINT64 : writeSInt64 (number, (Long )value); break;
+ case DOUBLE : writeDoubleNoTag ((Double ) value); break;
+ case FLOAT : writeFloatNoTag ((Float ) value); break;
+ case INT64 : writeInt64NoTag ((Long ) value); break;
+ case UINT64 : writeUInt64NoTag ((Long ) value); break;
+ case INT32 : writeInt32NoTag ((Integer ) value); break;
+ case FIXED64 : writeFixed64NoTag ((Long ) value); break;
+ case FIXED32 : writeFixed32NoTag ((Integer ) value); break;
+ case BOOL : writeBoolNoTag ((Boolean ) value); break;
+ case STRING : writeStringNoTag ((String ) value); break;
+ case GROUP : writeGroupNoTag ((Message ) value); break;
+ case MESSAGE : writeMessageNoTag ((Message ) value); break;
+ case BYTES : writeBytesNoTag ((ByteString) value); break;
+ case UINT32 : writeUInt32NoTag ((Integer ) value); break;
+ case SFIXED32: writeSFixed32NoTag((Integer ) value); break;
+ case SFIXED64: writeSFixed64NoTag((Long ) value); break;
+ case SINT32 : writeSInt32NoTag ((Integer ) value); break;
+ case SINT64 : writeSInt64NoTag ((Long ) value); break;
case ENUM:
- writeEnum(number, ((Descriptors.EnumValueDescriptor)value).getNumber());
+ writeEnumNoTag(((Descriptors.EnumValueDescriptor) value).getNumber());
break;
}
}
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field to the stream. */
+ public void writeDoubleNoTag(double value) throws IOException {
+ writeRawLittleEndian64(Double.doubleToRawLongBits(value));
+ }
+
+ /** Write a {@code float} field to the stream. */
+ public void writeFloatNoTag(float value) throws IOException {
+ writeRawLittleEndian32(Float.floatToRawIntBits(value));
+ }
+
+ /** Write a {@code uint64} field to the stream. */
+ public void writeUInt64NoTag(long value) throws IOException {
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int64} field to the stream. */
+ public void writeInt64NoTag(long value) throws IOException {
+ writeRawVarint64(value);
+ }
+
+ /** Write an {@code int32} field to the stream. */
+ public void writeInt32NoTag(int value) throws IOException {
+ if (value >= 0) {
+ writeRawVarint32(value);
+ } else {
+ // Must sign-extend.
+ writeRawVarint64(value);
+ }
+ }
+
+ /** Write a {@code fixed64} field to the stream. */
+ public void writeFixed64NoTag(long value) throws IOException {
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write a {@code fixed32} field to the stream. */
+ public void writeFixed32NoTag(int value) throws IOException {
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write a {@code bool} field to the stream. */
+ public void writeBoolNoTag(boolean value) throws IOException {
+ writeRawByte(value ? 1 : 0);
+ }
+
+ /** Write a {@code string} field to the stream. */
+ public void writeStringNoTag(String value) throws IOException {
+ // Unfortunately there does not appear to be any way to tell Java to encode
+ // UTF-8 directly into our buffer, so we have to let it create its own byte
+ // array and then copy.
+ byte[] bytes = value.getBytes("UTF-8");
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code group} field to the stream. */
+ public void writeGroupNoTag(Message value) throws IOException {
+ value.writeTo(this);
+ }
+
+ /** Write a group represented by an {@link UnknownFieldSet}. */
+ public void writeUnknownGroupNoTag(UnknownFieldSet value)
+ throws IOException {
+ value.writeTo(this);
+ }
+
+ /** Write an embedded message field to the stream. */
+ public void writeMessageNoTag(Message value) throws IOException {
+ writeRawVarint32(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ /** Write a {@code bytes} field to the stream. */
+ public void writeBytesNoTag(ByteString value) throws IOException {
+ byte[] bytes = value.toByteArray();
+ writeRawVarint32(bytes.length);
+ writeRawBytes(bytes);
+ }
+
+ /** Write a {@code uint32} field to the stream. */
+ public void writeUInt32NoTag(int value) throws IOException {
+ writeRawVarint32(value);
+ }
+
+ /**
+ * Write an enum field to the stream. Caller is responsible
+ * for converting the enum value to its numeric value.
+ */
+ public void writeEnumNoTag(int value) throws IOException {
+ writeRawVarint32(value);
+ }
+
+ /** Write an {@code sfixed32} field to the stream. */
+ public void writeSFixed32NoTag(int value) throws IOException {
+ writeRawLittleEndian32(value);
+ }
+
+ /** Write an {@code sfixed64} field to the stream. */
+ public void writeSFixed64NoTag(long value) throws IOException {
+ writeRawLittleEndian64(value);
+ }
+
+ /** Write an {@code sint32} field to the stream. */
+ public void writeSInt32NoTag(int value) throws IOException {
+ writeRawVarint32(encodeZigZag32(value));
+ }
+
+ /** Write an {@code sint64} field to the stream. */
+ public void writeSInt64NoTag(long value) throws IOException {
+ writeRawVarint64(encodeZigZag64(value));
+ }
+
// =================================================================
/**
@@ -316,7 +439,7 @@ public final class CodedOutputStream {
* {@code double} field, including tag.
*/
public static int computeDoubleSize(int fieldNumber, double value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
}
/**
@@ -324,7 +447,7 @@ public final class CodedOutputStream {
* {@code float} field, including tag.
*/
public static int computeFloatSize(int fieldNumber, float value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
}
/**
@@ -332,7 +455,7 @@ public final class CodedOutputStream {
* {@code uint64} field, including tag.
*/
public static int computeUInt64Size(int fieldNumber, long value) {
- return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
}
/**
@@ -340,7 +463,7 @@ public final class CodedOutputStream {
* {@code int64} field, including tag.
*/
public static int computeInt64Size(int fieldNumber, long value) {
- return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
+ return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
}
/**
@@ -348,12 +471,7 @@ public final class CodedOutputStream {
* {@code int32} field, including tag.
*/
public static int computeInt32Size(int fieldNumber, int value) {
- if (value >= 0) {
- return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
- } else {
- // Must sign-extend.
- return computeTagSize(fieldNumber) + 10;
- }
+ return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
}
/**
@@ -361,7 +479,7 @@ public final class CodedOutputStream {
* {@code fixed64} field, including tag.
*/
public static int computeFixed64Size(int fieldNumber, long value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
}
/**
@@ -369,7 +487,7 @@ public final class CodedOutputStream {
* {@code fixed32} field, including tag.
*/
public static int computeFixed32Size(int fieldNumber, int value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
}
/**
@@ -377,7 +495,7 @@ public final class CodedOutputStream {
* {@code bool} field, including tag.
*/
public static int computeBoolSize(int fieldNumber, boolean value) {
- return computeTagSize(fieldNumber) + 1;
+ return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
}
/**
@@ -385,14 +503,7 @@ public final class CodedOutputStream {
* {@code string} field, including tag.
*/
public static int computeStringSize(int fieldNumber, String value) {
- try {
- byte[] bytes = value.getBytes("UTF-8");
- return computeTagSize(fieldNumber) +
- computeRawVarint32Size(bytes.length) +
- bytes.length;
- } catch (java.io.UnsupportedEncodingException e) {
- throw new RuntimeException("UTF-8 not supported.", e);
- }
+ return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
}
/**
@@ -400,7 +511,7 @@ public final class CodedOutputStream {
* {@code group} field, including tag.
*/
public static int computeGroupSize(int fieldNumber, Message value) {
- return computeTagSize(fieldNumber) * 2 + value.getSerializedSize();
+ return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
/**
@@ -410,7 +521,8 @@ public final class CodedOutputStream {
*/
public static int computeUnknownGroupSize(int fieldNumber,
UnknownFieldSet value) {
- return computeTagSize(fieldNumber) * 2 + value.getSerializedSize();
+ return computeTagSize(fieldNumber) * 2 +
+ computeUnknownGroupSizeNoTag(value);
}
/**
@@ -418,8 +530,7 @@ public final class CodedOutputStream {
* embedded message field, including tag.
*/
public static int computeMessageSize(int fieldNumber, Message value) {
- int size = value.getSerializedSize();
- return computeTagSize(fieldNumber) + computeRawVarint32Size(size) + size;
+ return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
}
/**
@@ -427,9 +538,7 @@ public final class CodedOutputStream {
* {@code bytes} field, including tag.
*/
public static int computeBytesSize(int fieldNumber, ByteString value) {
- return computeTagSize(fieldNumber) +
- computeRawVarint32Size(value.size()) +
- value.size();
+ return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
}
/**
@@ -437,7 +546,7 @@ public final class CodedOutputStream {
* {@code uint32} field, including tag.
*/
public static int computeUInt32Size(int fieldNumber, int value) {
- return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
}
/**
@@ -446,7 +555,7 @@ public final class CodedOutputStream {
* enum value to its numeric value.
*/
public static int computeEnumSize(int fieldNumber, int value) {
- return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
+ return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
}
/**
@@ -454,7 +563,7 @@ public final class CodedOutputStream {
* {@code sfixed32} field, including tag.
*/
public static int computeSFixed32Size(int fieldNumber, int value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
+ return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
}
/**
@@ -462,7 +571,7 @@ public final class CodedOutputStream {
* {@code sfixed64} field, including tag.
*/
public static int computeSFixed64Size(int fieldNumber, long value) {
- return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
+ return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
}
/**
@@ -470,8 +579,7 @@ public final class CodedOutputStream {
* {@code sint32} field, including tag.
*/
public static int computeSInt32Size(int fieldNumber, int value) {
- return computeTagSize(fieldNumber) +
- computeRawVarint32Size(encodeZigZag32(value));
+ return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
}
/**
@@ -479,8 +587,7 @@ public final class CodedOutputStream {
* {@code sint64} field, including tag.
*/
public static int computeSInt64Size(int fieldNumber, long value) {
- return computeTagSize(fieldNumber) +
- computeRawVarint64Size(encodeZigZag64(value));
+ return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
}
/**
@@ -507,6 +614,174 @@ public final class CodedOutputStream {
computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
}
+ // -----------------------------------------------------------------
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code double} field, including tag.
+ */
+ public static int computeDoubleSizeNoTag(double value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code float} field, including tag.
+ */
+ public static int computeFloatSizeNoTag(float value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint64} field, including tag.
+ */
+ public static int computeUInt64SizeNoTag(long value) {
+ return computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int64} field, including tag.
+ */
+ public static int computeInt64SizeNoTag(long value) {
+ return computeRawVarint64Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int32} field, including tag.
+ */
+ public static int computeInt32SizeNoTag(int value) {
+ if (value >= 0) {
+ return computeRawVarint32Size(value);
+ } else {
+ // Must sign-extend.
+ return 10;
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed64} field.
+ */
+ public static int computeFixed64SizeNoTag(long value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code fixed32} field.
+ */
+ public static int computeFixed32SizeNoTag(int value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bool} field.
+ */
+ public static int computeBoolSizeNoTag(boolean value) {
+ return 1;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code string} field.
+ */
+ public static int computeStringSizeNoTag(String value) {
+ try {
+ byte[] bytes = value.getBytes("UTF-8");
+ return computeRawVarint32Size(bytes.length) +
+ bytes.length;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field.
+ */
+ public static int computeGroupSizeNoTag(Message value) {
+ return value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field represented by an {@code UnknownFieldSet}, including
+ * tag.
+ */
+ public static int computeUnknownGroupSizeNoTag(UnknownFieldSet value) {
+ return value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an embedded
+ * message field.
+ */
+ public static int computeMessageSizeNoTag(Message value) {
+ int size = value.getSerializedSize();
+ return computeRawVarint32Size(size) + size;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field.
+ */
+ public static int computeBytesSizeNoTag(ByteString value) {
+ return computeRawVarint32Size(value.size()) +
+ value.size();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint32} field.
+ */
+ public static int computeUInt32SizeNoTag(int value) {
+ return computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an enum field.
+ * Caller is responsible for converting the enum value to its numeric value.
+ */
+ public static int computeEnumSizeNoTag(int value) {
+ return computeRawVarint32Size(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed32} field.
+ */
+ public static int computeSFixed32SizeNoTag(int value) {
+ return LITTLE_ENDIAN_32_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed64} field.
+ */
+ public static int computeSFixed64SizeNoTag(long value) {
+ return LITTLE_ENDIAN_64_SIZE;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint32} field.
+ */
+ public static int computeSInt32SizeNoTag(int value) {
+ return computeRawVarint32Size(encodeZigZag32(value));
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint64} field.
+ */
+ public static int computeSInt64SizeNoTag(long value) {
+ return computeRawVarint64Size(encodeZigZag64(value));
+ }
+
/**
* Compute the number of bytes that would be needed to encode a
* field of arbitrary type, including tag, to the stream.
@@ -521,28 +796,48 @@ public final class CodedOutputStream {
public static int computeFieldSize(
Descriptors.FieldDescriptor.Type type,
int number, Object value) {
+ int tagSize = computeTagSize(number);
+ if (type == Descriptors.FieldDescriptor.Type.GROUP) {
+ tagSize *= 2;
+ }
+ return tagSize + computeFieldSizeNoTag(type, value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * field of arbitrary type, excluding tag, to the stream.
+ *
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public static int computeFieldSizeNoTag(
+ Descriptors.FieldDescriptor.Type type, Object value) {
switch (type) {
- case DOUBLE : return computeDoubleSize (number, (Double )value);
- case FLOAT : return computeFloatSize (number, (Float )value);
- case INT64 : return computeInt64Size (number, (Long )value);
- case UINT64 : return computeUInt64Size (number, (Long )value);
- case INT32 : return computeInt32Size (number, (Integer )value);
- case FIXED64 : return computeFixed64Size (number, (Long )value);
- case FIXED32 : return computeFixed32Size (number, (Integer )value);
- case BOOL : return computeBoolSize (number, (Boolean )value);
- case STRING : return computeStringSize (number, (String )value);
- case GROUP : return computeGroupSize (number, (Message )value);
- case MESSAGE : return computeMessageSize (number, (Message )value);
- case BYTES : return computeBytesSize (number, (ByteString)value);
- case UINT32 : return computeUInt32Size (number, (Integer )value);
- case SFIXED32: return computeSFixed32Size(number, (Integer )value);
- case SFIXED64: return computeSFixed64Size(number, (Long )value);
- case SINT32 : return computeSInt32Size (number, (Integer )value);
- case SINT64 : return computeSInt64Size (number, (Long )value);
+ case DOUBLE : return computeDoubleSizeNoTag ((Double )value);
+ case FLOAT : return computeFloatSizeNoTag ((Float )value);
+ case INT64 : return computeInt64SizeNoTag ((Long )value);
+ case UINT64 : return computeUInt64SizeNoTag ((Long )value);
+ case INT32 : return computeInt32SizeNoTag ((Integer )value);
+ case FIXED64 : return computeFixed64SizeNoTag ((Long )value);
+ case FIXED32 : return computeFixed32SizeNoTag ((Integer )value);
+ case BOOL : return computeBoolSizeNoTag ((Boolean )value);
+ case STRING : return computeStringSizeNoTag ((String )value);
+ case GROUP : return computeGroupSizeNoTag ((Message )value);
+ case MESSAGE : return computeMessageSizeNoTag ((Message )value);
+ case BYTES : return computeBytesSizeNoTag ((ByteString)value);
+ case UINT32 : return computeUInt32SizeNoTag ((Integer )value);
+ case SFIXED32: return computeSFixed32SizeNoTag((Integer )value);
+ case SFIXED64: return computeSFixed64SizeNoTag((Long )value);
+ case SINT32 : return computeSInt32SizeNoTag ((Integer )value);
+ case SINT64 : return computeSInt64SizeNoTag ((Long )value);
case ENUM:
- return computeEnumSize(number,
- ((Descriptors.EnumValueDescriptor)value).getNumber());
+ return computeEnumSizeNoTag(
+ ((Descriptors.EnumValueDescriptor)value).getNumber());
}
throw new RuntimeException(
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
index ee4d4e3a..80266a59 100644
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/src/main/java/com/google/protobuf/Descriptors.java
@@ -857,6 +857,19 @@ public final class Descriptors {
"Field numbers must be positive integers.");
}
+ // Only repeated primitive fields may be packed.
+ if (proto.getOptions().getPacked()) {
+ if (proto.getLabel() != FieldDescriptorProto.Label.LABEL_REPEATED ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_STRING ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_GROUP ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_BYTES) {
+ throw new DescriptorValidationException(this,
+ "[packed = true] can only be specified for repeated primitive " +
+ "fields.");
+ }
+ }
+
if (isExtension) {
if (!proto.hasExtendee()) {
throw new DescriptorValidationException(this,
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java
index fefa23ec..99ae253c 100644
--- a/java/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -211,6 +211,10 @@ public final class DynamicMessage extends AbstractMessage {
return new Builder(type);
}
+ public Builder toBuilder() {
+ return newBuilderForType().mergeFrom(this);
+ }
+
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
@@ -251,6 +255,7 @@ public final class DynamicMessage extends AbstractMessage {
}
fields.mergeFrom(other);
+ mergeUnknownFields(other.getUnknownFields());
return this;
}
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java
index 98a1c328..01da3faf 100644
--- a/java/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/src/main/java/com/google/protobuf/FieldSet.java
@@ -351,8 +351,7 @@ final class FieldSet {
setField(field, entry.getValue());
} else {
setField(field,
- existingValue.newBuilderForType()
- .mergeFrom(existingValue)
+ existingValue.toBuilder()
.mergeFrom((Message)entry.getValue())
.build());
}
@@ -384,8 +383,7 @@ final class FieldSet {
setField(field, value);
} else {
setField(field,
- existingValue.newBuilderForType()
- .mergeFrom(existingValue)
+ existingValue.toBuilder()
.mergeFrom((Message)value)
.build());
}
@@ -463,60 +461,83 @@ final class FieldSet {
}
if (field == null ||
- wireType != WireFormat.getWireFormatForFieldType(field.getType())) {
+ wireType != WireFormat.getWireFormatForField(field)) {
// Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input);
} else {
- Object value;
- switch (field.getType()) {
- case GROUP: {
- Message.Builder subBuilder;
- if (defaultInstance != null) {
- subBuilder = defaultInstance.newBuilderForType();
- } else {
- subBuilder = builder.newBuilderForField(field);
+ if (field.getOptions().getPacked()) {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ if (field.getType() == FieldDescriptor.Type.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ int rawValue = input.readEnum();
+ Object value = field.getEnumType().findValueByNumber(rawValue);
+ if (value == null) {
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
+ return true;
+ }
+ builder.addRepeatedField(field, value);
}
- if (!field.isRepeated()) {
- subBuilder.mergeFrom((Message) builder.getField(field));
+ } else {
+ while (input.getBytesUntilLimit() > 0) {
+ Object value = input.readPrimitiveField(field.getType());
+ builder.addRepeatedField(field, value);
}
- input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
- value = subBuilder.build();
- break;
}
- case MESSAGE: {
- Message.Builder subBuilder;
- if (defaultInstance != null) {
- subBuilder = defaultInstance.newBuilderForType();
- } else {
- subBuilder = builder.newBuilderForField(field);
+ input.popLimit(limit);
+ } else {
+ Object value;
+ switch (field.getType()) {
+ case GROUP: {
+ Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
}
- if (!field.isRepeated()) {
- subBuilder.mergeFrom((Message) builder.getField(field));
+ case MESSAGE: {
+ Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
}
- input.readMessage(subBuilder, extensionRegistry);
- value = subBuilder.build();
- break;
- }
- case ENUM: {
- int rawValue = input.readEnum();
- value = field.getEnumType().findValueByNumber(rawValue);
- // If the number isn't recognized as a valid value for this enum,
- // drop it.
- if (value == null) {
- unknownFields.mergeVarintField(fieldNumber, rawValue);
- return true;
+ case ENUM: {
+ int rawValue = input.readEnum();
+ value = field.getEnumType().findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ unknownFields.mergeVarintField(fieldNumber, rawValue);
+ return true;
+ }
+ break;
}
- break;
+ default:
+ value = input.readPrimitiveField(field.getType());
+ break;
}
- default:
- value = input.readPrimitiveField(field.getType());
- break;
- }
- if (field.isRepeated()) {
- builder.addRepeatedField(field, value);
- } else {
- builder.setField(field, value);
+ if (field.isRepeated()) {
+ builder.addRepeatedField(field, value);
+ } else {
+ builder.setField(field, value);
+ }
}
}
@@ -636,8 +657,24 @@ final class FieldSet {
output.writeMessageSetExtension(field.getNumber(), (Message)value);
} else {
if (field.isRepeated()) {
- for (Object element : (List)value) {
- output.writeField(field.getType(), field.getNumber(), element);
+ List valueList = (List)value;
+ if (field.getOptions().getPacked()) {
+ output.writeTag(field.getNumber(),
+ WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ // Compute the total data size so the length can be written.
+ int dataSize = 0;
+ for (Object element : valueList) {
+ dataSize += output.computeFieldSizeNoTag(field.getType(), element);
+ }
+ output.writeRawVarint32(dataSize);
+ // Write the data itself, without any tags.
+ for (Object element : valueList) {
+ output.writeFieldNoTag(field.getType(), element);
+ }
+ } else {
+ for (Object element : valueList) {
+ output.writeField(field.getType(), field.getNumber(), element);
+ }
}
} else {
output.writeField(field.getType(), field.getNumber(), value);
@@ -658,12 +695,23 @@ final class FieldSet {
if (field.isExtension() &&
field.getContainingType().getOptions().getMessageSetWireFormat()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
- field.getNumber(), (Message)value);
+ field.getNumber(), (Message) value);
} else {
if (field.isRepeated()) {
- for (Object element : (List)value) {
- size += CodedOutputStream.computeFieldSize(
- field.getType(), field.getNumber(), element);
+ if (field.getOptions().getPacked()) {
+ int dataSize = 0;
+ for (Object element : (List)value) {
+ dataSize += CodedOutputStream.computeFieldSizeNoTag(
+ field.getType(), element);
+ }
+ size += dataSize +
+ CodedOutputStream.computeTagSize(field.getNumber()) +
+ CodedOutputStream.computeRawVarint32Size(dataSize);
+ } else {
+ for (Object element : (List)value) {
+ size += CodedOutputStream.computeFieldSize(
+ field.getType(), field.getNumber(), element);
+ }
}
} else {
size += CodedOutputStream.computeFieldSize(
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
index b1be8b14..77c88c30 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -31,8 +31,8 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
@@ -75,7 +75,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
for (FieldDescriptor field : descriptor.getFields()) {
if (field.isRepeated()) {
- List value = (List)getField(field);
+ List value = (List) getField(field);
if (!value.isEmpty()) {
result.put(field, value);
}
@@ -87,7 +87,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
}
return result;
}
-
+
public boolean isInitialized() {
for (FieldDescriptor field : getDescriptorForType().getFields()) {
// Check that all required fields are present.
@@ -99,7 +99,9 @@ public abstract class GeneratedMessage extends AbstractMessage {
// Check that embedded messages are initialized.
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
- for (Message element : (List<Message>) getField(field)) {
+ @SuppressWarnings("unchecked")
+ List<Message> messageList = (List<Message>) getField(field);
+ for (Message element : messageList) {
if (!element.isInitialized()) {
return false;
}
@@ -189,7 +191,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
setField(field, entry.getValue());
}
}
- return (BuilderType)this;
+ return (BuilderType) this;
}
public Descriptor getDescriptorForType() {
@@ -214,7 +216,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
// The underlying list object is still modifiable at this point.
// Make sure not to expose the modifiable list to the caller.
return Collections.unmodifiableList(
- (List)internalGetResult().getField(field));
+ (List) internalGetResult().getField(field));
} else {
return internalGetResult().getField(field);
}
@@ -223,12 +225,12 @@ public abstract class GeneratedMessage extends AbstractMessage {
public BuilderType setField(Descriptors.FieldDescriptor field,
Object value) {
internalGetFieldAccessorTable().getField(field).set(this, value);
- return (BuilderType)this;
+ return (BuilderType) this;
}
public BuilderType clearField(Descriptors.FieldDescriptor field) {
internalGetFieldAccessorTable().getField(field).clear(this);
- return (BuilderType)this;
+ return (BuilderType) this;
}
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
@@ -244,13 +246,13 @@ public abstract class GeneratedMessage extends AbstractMessage {
int index, Object value) {
internalGetFieldAccessorTable().getField(field)
.setRepeated(this, index, value);
- return (BuilderType)this;
+ return (BuilderType) this;
}
public BuilderType addRepeatedField(Descriptors.FieldDescriptor field,
Object value) {
internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
- return (BuilderType)this;
+ return (BuilderType) this;
}
public final UnknownFieldSet getUnknownFields() {
@@ -259,7 +261,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
public final BuilderType setUnknownFields(UnknownFieldSet unknownFields) {
internalGetResult().unknownFields = unknownFields;
- return (BuilderType)this;
+ return (BuilderType) this;
}
public final BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) {
@@ -268,7 +270,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
UnknownFieldSet.newBuilder(result.unknownFields)
.mergeFrom(unknownFields)
.build();
- return (BuilderType)this;
+ return (BuilderType) this;
}
public boolean isInitialized() {
@@ -287,7 +289,18 @@ public abstract class GeneratedMessage extends AbstractMessage {
return unknownFields.mergeFieldFrom(tag, input);
}
+ /**
+ * Adds the {@code values} to the {@code list}.
+ *
+ * @throws NullPointerException if any of the elements of {@code values} is
+ * null.
+ */
protected <T> void addAll(Iterable<T> values, Collection<? super T> list) {
+ for (T value : values) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ }
if (values instanceof Collection) {
@SuppressWarnings("unsafe")
Collection<T> collection = (Collection<T>) values;
@@ -378,9 +391,9 @@ public abstract class GeneratedMessage extends AbstractMessage {
verifyExtensionContainingType(extension);
Object value = extensions.getField(extension.getDescriptor());
if (value == null) {
- return (Type)extension.getMessageDefaultInstance();
+ return (Type) extension.getMessageDefaultInstance();
} else {
- return (Type)extension.fromReflectionType(value);
+ return (Type) extension.fromReflectionType(value);
}
}
@@ -389,7 +402,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
public final <Type> Type getExtension(
GeneratedExtension<MessageType, List<Type>> extension, int index) {
verifyExtensionContainingType(extension);
- return (Type)extension.singularFromReflectionType(
+ return (Type) extension.singularFromReflectionType(
extensions.getRepeatedField(extension.getDescriptor(), index));
}
@@ -397,7 +410,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
protected boolean extensionsAreInitialized() {
return extensions.isInitialized();
}
-
+
public boolean isInitialized() {
return super.isInitialized() && extensionsAreInitialized();
}
@@ -580,7 +593,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
message.verifyExtensionContainingType(extension);
message.extensions.setField(extension.getDescriptor(),
extension.toReflectionType(value));
- return (BuilderType)this;
+ return (BuilderType) this;
}
/** Set the value of one element of a repeated extension. */
@@ -592,7 +605,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
message.extensions.setRepeatedField(
extension.getDescriptor(), index,
extension.singularToReflectionType(value));
- return (BuilderType)this;
+ return (BuilderType) this;
}
/** Append a value to a repeated extension. */
@@ -602,7 +615,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
message.verifyExtensionContainingType(extension);
message.extensions.addRepeatedField(
extension.getDescriptor(), extension.singularToReflectionType(value));
- return (BuilderType)this;
+ return (BuilderType) this;
}
/** Clear an extension. */
@@ -611,7 +624,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.clearField(extension.getDescriptor());
- return (BuilderType)this;
+ return (BuilderType) this;
}
/**
@@ -639,7 +652,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
ExtendableMessage<MessageType> message = internalGetResult();
message.verifyContainingType(field);
message.extensions.setField(field, value);
- return (BuilderType)this;
+ return (BuilderType) this;
} else {
return super.setField(field, value);
}
@@ -650,7 +663,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
ExtendableMessage<MessageType> message = internalGetResult();
message.verifyContainingType(field);
message.extensions.clearField(field);
- return (BuilderType)this;
+ return (BuilderType) this;
} else {
return super.clearField(field);
}
@@ -662,7 +675,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
ExtendableMessage<MessageType> message = internalGetResult();
message.verifyContainingType(field);
message.extensions.setRepeatedField(field, index, value);
- return (BuilderType)this;
+ return (BuilderType) this;
} else {
return super.setRepeatedField(field, index, value);
}
@@ -674,11 +687,15 @@ public abstract class GeneratedMessage extends AbstractMessage {
ExtendableMessage<MessageType> message = internalGetResult();
message.verifyContainingType(field);
message.extensions.addRepeatedField(field, value);
- return (BuilderType)this;
+ return (BuilderType) this;
} else {
return super.addRepeatedField(field, value);
}
}
+
+ protected final void mergeExtensionFields(ExtendableMessage other) {
+ internalGetResult().extensions.mergeFrom(other.extensions);
+ }
}
// -----------------------------------------------------------------
@@ -750,8 +767,8 @@ public abstract class GeneratedMessage extends AbstractMessage {
enumValueOf = null;
enumGetValueDescriptor = null;
messageDefaultInstance =
- (Message)invokeOrDie(getMethodOrDie(type, "getDefaultInstance"),
- null);
+ (Message) invokeOrDie(getMethodOrDie(type, "getDefaultInstance"),
+ null);
break;
case ENUM:
enumValueOf = getMethodOrDie(type, "valueOf",
@@ -797,7 +814,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
// Must convert the whole list.
List result = new ArrayList();
- for (Object element : (List)value) {
+ for (Object element : (List) value) {
result.add(singularFromReflectionType(element));
}
return result;
@@ -826,10 +843,10 @@ public abstract class GeneratedMessage extends AbstractMessage {
// This should not happen in normal use. But, to be nice, we'll
// copy the message to whatever type the caller was expecting.
return messageDefaultInstance.newBuilderForType()
- .mergeFrom((Message)value).build();
+ .mergeFrom((Message) value).build();
}
case ENUM:
- return invokeOrDie(enumValueOf, null, (EnumValueDescriptor)value);
+ return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
default:
return value;
}
@@ -847,7 +864,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
// Must convert the whole list.
List result = new ArrayList();
- for (Object element : (List)value) {
+ for (Object element : (List) value) {
result.add(singularToReflectionType(element));
}
return result;
@@ -900,9 +917,9 @@ public abstract class GeneratedMessage extends AbstractMessage {
} catch (java.lang.reflect.InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
- throw (RuntimeException)cause;
+ throw (RuntimeException) cause;
} else if (cause instanceof Error) {
- throw (Error)cause;
+ throw (Error) cause;
} else {
throw new RuntimeException(
"Unexpected exception thrown by generated accessor method.", cause);
@@ -915,6 +932,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
* with access to the fields of a message object using Java reflection.
*/
public static final class FieldAccessorTable {
+
/**
* Construct a FieldAccessorTable for a particular message class. Only
* one FieldAccessorTable should ever be constructed per class.
@@ -1039,7 +1057,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
"addRepeatedField() called on a singular field.");
}
public boolean has(GeneratedMessage message) {
- return (Boolean)invokeOrDie(hasMethod, message);
+ return (Boolean) invokeOrDie(hasMethod, message);
}
public int getRepeatedCount(GeneratedMessage message) {
throw new UnsupportedOperationException(
@@ -1092,7 +1110,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
// 2) Insures that the caller cannot modify the list later on and
// have the modifications be reflected in the message.
clear(builder);
- for (Object element : (List)value) {
+ for (Object element : (List) value) {
addRepeated(builder, element);
}
}
@@ -1111,7 +1129,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
"hasField() called on a singular field.");
}
public int getRepeatedCount(GeneratedMessage message) {
- return (Integer)invokeOrDie(getCountMethod, message);
+ return (Integer) invokeOrDie(getCountMethod, message);
}
public void clear(GeneratedMessage.Builder builder) {
invokeOrDie(clearMethod, builder);
@@ -1169,7 +1187,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
@SuppressWarnings("unchecked")
public Object get(GeneratedMessage message) {
List newList = new ArrayList();
- for (Object element : (List)super.get(message)) {
+ for (Object element : (List) super.get(message)) {
newList.add(invokeOrDie(getValueDescriptorMethod, element));
}
return Collections.unmodifiableList(newList);
@@ -1210,8 +1228,8 @@ public abstract class GeneratedMessage extends AbstractMessage {
// is an alternative implementation of the same type -- e.g. a
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
- return ((Message.Builder)invokeOrDie(newBuilderMethod, null))
- .mergeFrom((Message)value).build();
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message) value).build();
}
}
@@ -1219,7 +1237,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
super.set(builder, coerceType(value));
}
public Message.Builder newBuilder() {
- return (Message.Builder)invokeOrDie(newBuilderMethod, null);
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
}
}
@@ -1244,8 +1262,8 @@ public abstract class GeneratedMessage extends AbstractMessage {
// is an alternative implementation of the same type -- e.g. a
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
- return ((Message.Builder)invokeOrDie(newBuilderMethod, null))
- .mergeFrom((Message)value).build();
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message) value).build();
}
}
@@ -1257,7 +1275,7 @@ public abstract class GeneratedMessage extends AbstractMessage {
super.addRepeated(builder, coerceType(value));
}
public Message.Builder newBuilder() {
- return (Message.Builder)invokeOrDie(newBuilderMethod, null);
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
}
}
}
diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java
index 9635387a..2f8700db 100644
--- a/java/src/main/java/com/google/protobuf/Message.java
+++ b/java/src/main/java/com/google/protobuf/Message.java
@@ -195,6 +195,12 @@ public interface Message {
Builder newBuilderForType();
/**
+ * Constructs a builder initialized with the current message. Use this to
+ * derive a new message from the current one.
+ */
+ Builder toBuilder();
+
+ /**
* Abstract interface implemented by Protocol Message builders.
*/
public static interface Builder extends Cloneable {
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index 3a1b1d4e..3dcf68c8 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -397,13 +397,15 @@ public final class TextFormat {
private int previousLine = 0;
private int previousColumn = 0;
+ // We use possesive quantifiers (*+ and ++) because otherwise the Java
+ // regex matcher has stack overflows on large inputs.
private static Pattern WHITESPACE =
- Pattern.compile("(\\s|(#.*$))+", Pattern.MULTILINE);
+ Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
private static Pattern TOKEN = Pattern.compile(
- "[a-zA-Z_][0-9a-zA-Z_+-]*|" + // an identifier
- "[0-9+-][0-9a-zA-Z_.+-]*|" + // a number
- "\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|" + // a double-quoted string
- "\'([^\"\n\\\\]|\\\\.)*(\'|\\\\?$)", // a single-quoted string
+ "[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier
+ "[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number
+ "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string
+ "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string
Pattern.MULTILINE);
private static Pattern DOUBLE_INFINITY = Pattern.compile(
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java
index ff042c05..2faf2448 100644
--- a/java/src/main/java/com/google/protobuf/WireFormat.java
+++ b/java/src/main/java/com/google/protobuf/WireFormat.java
@@ -96,6 +96,16 @@ public final class WireFormat {
"There is no way to get here, but the compiler thinks otherwise.");
}
+ /** Given a field descriptor, returns the wire type. This differs from
+ * getWireFormatForFieldType for packed repeated fields. */
+ static int getWireFormatForField(Descriptors.FieldDescriptor descriptor) {
+ if (descriptor.getOptions().getPacked()) {
+ return WIRETYPE_LENGTH_DELIMITED;
+ } else {
+ return getWireFormatForFieldType(descriptor.getType());
+ }
+ }
+
// Field numbers for feilds in MessageSet wire format.
static final int MESSAGE_SET_ITEM = 1;
static final int MESSAGE_SET_TYPE_ID = 2;