aboutsummaryrefslogtreecommitdiff
path: root/java/src/main
diff options
context:
space:
mode:
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;