/** * Reads and discards a single field, given its tag value. * * @return {@code false} if the tag is an endgroup tag, in which case nothing is skipped. * Otherwise, returns {@code true}. */ public boolean skipField(final int tag) throws IOException { switch (WireFormat.getTagWireType(tag)) { case WireFormat.WIRETYPE_VARINT: skipRawVarint(); return true; case WireFormat.WIRETYPE_FIXED64: skipRawBytes(8); return true; case WireFormat.WIRETYPE_LENGTH_DELIMITED: skipRawBytes(readRawVarint32()); return true; case WireFormat.WIRETYPE_START_GROUP: skipMessage(); checkLastTagWas( WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP)); return true; case WireFormat.WIRETYPE_END_GROUP: return false; case WireFormat.WIRETYPE_FIXED32: skipRawBytes(4); return true; default: throw InvalidProtocolBufferException.invalidWireType(); } }
/** * Reads a single field and writes it to output in wire format, given its tag value. * * @return {@code false} if the tag is an endgroup tag, in which case nothing is skipped. * Otherwise, returns {@code true}. */ public boolean skipField(final int tag, final CodedOutputStream output) throws IOException { switch (WireFormat.getTagWireType(tag)) { case WireFormat.WIRETYPE_VARINT: { long value = readInt64(); output.writeRawVarint32(tag); output.writeUInt64NoTag(value); return true; } case WireFormat.WIRETYPE_FIXED64: { long value = readRawLittleEndian64(); output.writeRawVarint32(tag); output.writeFixed64NoTag(value); return true; } case WireFormat.WIRETYPE_LENGTH_DELIMITED: { ByteString value = readBytes(); output.writeRawVarint32(tag); output.writeBytesNoTag(value); return true; } case WireFormat.WIRETYPE_START_GROUP: { output.writeRawVarint32(tag); skipMessage(output); int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP); checkLastTagWas(endtag); output.writeRawVarint32(endtag); return true; } case WireFormat.WIRETYPE_END_GROUP: { return false; } case WireFormat.WIRETYPE_FIXED32: { int value = readRawLittleEndian32(); output.writeRawVarint32(tag); output.writeFixed32NoTag(value); return true; } default: throw InvalidProtocolBufferException.invalidWireType(); } }
private static void printUnknownFieldValue(final int tag, final Object value, final TextGenerator generator) throws IOException { switch (WireFormat.getTagWireType(tag)) { case WireFormat.WIRETYPE_VARINT: generator.print(unsignedToString((Long) value)); break; case WireFormat.WIRETYPE_FIXED32: generator.print( String.format((Locale) null, "0x%08x", (Integer) value)); break; case WireFormat.WIRETYPE_FIXED64: generator.print(String.format((Locale) null, "0x%016x", (Long) value)); break; case WireFormat.WIRETYPE_LENGTH_DELIMITED: generator.print("\""); generator.print(escapeBytes((ByteString) value)); generator.print("\""); break; case WireFormat.WIRETYPE_START_GROUP: DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator); break; default: throw new IllegalArgumentException("Bad tag: " + tag); } }
@Override public <E> E readObject(String fieldName, Class<E> clazz) throws IOException { final FieldDescriptor fd = messageContext.marshallerDelegate.getFieldByName(fieldName); checkFieldRead(fd, false); if (fd.getType() == Type.ENUM) { return ctx.getMarshallerDelegate(clazz).unmarshall(fd, this, messageContext.in); } // todo validate type is compatible with readObject final int expectedTag = WireFormat.makeTag(fd.getNumber(), fd.getType().getWireType()); Object o = messageContext.unknownFieldSet.consumeTag(expectedTag); if (o != null) { byte[] byteArray = (byte[]) o; return readNestedObject( fd, clazz, RawProtoStreamReaderImpl.newInstance(byteArray), byteArray.length); } while (true) { int tag = messageContext.in.readTag(); if (tag == 0) { break; } if (tag == expectedTag) { return readNestedObject(fd, clazz, messageContext.in, -1); } messageContext.unknownFieldSet.readSingleField(tag, messageContext.in); } return null; }
public void testBool() throws Exception { int num = 1; boolean value = true; int valueSize = 1; int tag = WireFormat.makeTag(num, FieldType.BOOL.wireType); int tagSize = CodedOutput.computeRawVarint32Size(tag); int expect = tagSize + valueSize; assertSize("boolean1", CodedOutput.computeBoolSize(num, value), expect); assertSize("boolean2", CodedOutput.getTagAndRawVarInt32Bytes(tag, 1).length, expect); }
/** Read a {@code group} field value from the stream. */ public <T extends MessageLite> T readGroup( final int fieldNumber, final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException { if (recursionDepth >= recursionLimit) { throw InvalidProtocolBufferException.recursionLimitExceeded(); } ++recursionDepth; T result = parser.parsePartialFrom(this, extensionRegistry); checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); --recursionDepth; return result; }
/** Read a {@code group} field value from the stream. */ public void readGroup( final int fieldNumber, final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry) throws IOException { if (recursionDepth >= recursionLimit) { throw InvalidProtocolBufferException.recursionLimitExceeded(); } ++recursionDepth; builder.mergeFrom(this, extensionRegistry); checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); --recursionDepth; }
/** * Attempt to read a field tag, returning zero if we have reached EOF. Protocol message parsers * use this to read tags, since a protocol message may legally end wherever a tag occurs, and zero * is not a valid tag number. */ public int readTag() throws IOException { if (isAtEnd()) { lastTag = 0; return 0; } lastTag = readRawVarint32(); if (WireFormat.getTagFieldNumber(lastTag) == 0) { // If we actually read zero (or any tag number corresponding to field // number zero), that's not a valid tag. throw InvalidProtocolBufferException.invalidTag(); } return lastTag; }
public int readFieldNumber(Schema schema) throws IOException { final int fieldNumber = input.readFieldNumber(schema); if (WireFormat.getTagWireType(((CodedInput) input).getLastTag()) == WireFormat.WIRETYPE_REFERENCE) { // a reference. lastRef = input.readUInt32(); messageReference = true; } else { // always unset. messageReference = false; } return fieldNumber; }
/** * Tests that if we readString invalid UTF-8 bytes, no exception is thrown. Instead, the invalid * bytes are replaced with the Unicode "replacement character" U+FFFD. */ public void testReadStringInvalidUtf8() throws Exception { ByteString.Output rawOutput = ByteString.newOutput(); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); output.writeRawVarint32(tag); output.writeRawVarint32(1); output.writeRawBytes(new byte[] {(byte) 0x80}); output.flush(); CodedInputStream input = rawOutput.toByteString().newCodedInput(); assertEquals(tag, input.readTag()); String text = input.readString(); assertEquals(0xfffd, text.charAt(0)); }
public void testRawLittleEndian64Bytes() throws Exception { String n1 = "double1", n2 = "double2"; for (int i = 0; i < doubleValues.length; ) { double[] inner = doubleValues[i++]; int num = i; for (int j = 0; j < inner.length; j++) { long value = Double.doubleToRawLongBits(inner[j]); int tag = WireFormat.makeTag(num, FieldType.DOUBLE.wireType); int tagSize = CodedOutput.computeRawVarint32Size(tag); int expect = tagSize + CodedOutput.LITTLE_ENDIAN_64_SIZE; assertSize(n1, CodedOutput.computeDoubleSize(num, inner[j]), expect); assertSize(n2, CodedOutput.getTagAndRawLittleEndian64Bytes(tag, value).length, expect); } } }
public void testRawVarInt32Bytes() throws Exception { String n1 = "int1", n2 = "int2"; for (int i = 0; i < int32values.length; ) { int[] inner = int32values[i++]; int num = i; for (int j = 0; j < inner.length; j++) { int value = inner[j]; int valueSize = CodedOutput.computeRawVarint32Size(value); int tag = WireFormat.makeTag(num, FieldType.INT32.wireType); int tagSize = CodedOutput.computeRawVarint32Size(tag); int expect = tagSize + valueSize; assertSize(n1, CodedOutput.computeInt32Size(num, value), expect); assertSize(n2, CodedOutput.getTagAndRawVarInt32Bytes(tag, value).length, expect); } } }
public void testRawLittleEndian32Bytes() throws Exception { String n1 = "float1", n2 = "float2"; for (int i = 0; i < floatValues.length; ) { float[] inner = floatValues[i++]; int num = i; for (int j = 0; j < inner.length; j++) { int value = Float.floatToRawIntBits(inner[j]); int valueSize = CodedOutput.LITTLE_ENDIAN_32_SIZE; int tag = WireFormat.makeTag(num, FieldType.FLOAT.wireType); int tagSize = CodedOutput.computeRawVarint32Size(tag); int expect = tagSize + valueSize; assertSize(n1, CodedOutput.computeFloatSize(num, inner[j]), expect); assertSize(n2, CodedOutput.getTagAndRawLittleEndian32Bytes(tag, value).length, expect); } } }
/** * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProtocolBufferException * is thrown. */ public void testReadStringRequireUtf8InvalidUtf8() throws Exception { ByteString.Output rawOutput = ByteString.newOutput(); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); output.writeRawVarint32(tag); output.writeRawVarint32(1); output.writeRawBytes(new byte[] {(byte) 0x80}); output.flush(); CodedInputStream input = rawOutput.toByteString().newCodedInput(); assertEquals(tag, input.readTag()); try { input.readStringRequireUtf8(); fail("Expected invalid UTF-8 exception."); } catch (InvalidProtocolBufferException exception) { assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); } }
public void testReadMaliciouslyLargeBlob() throws Exception { ByteString.Output rawOutput = ByteString.newOutput(); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); output.writeRawVarint32(tag); output.writeRawVarint32(0x7FFFFFFF); output.writeRawBytes(new byte[32]); // Pad with a few random bytes. output.flush(); CodedInputStream input = rawOutput.toByteString().newCodedInput(); assertEquals(tag, input.readTag()); try { input.readBytes(); fail("Should have thrown an exception!"); } catch (InvalidProtocolBufferException e) { // success. } }
/** * Read an Object or an Enum. * * @param length the actual length of the nested object or -1 if the length should be read from * the stream */ private <A> A readNestedObject( FieldDescriptor fd, Class<A> clazz, RawProtoStreamReader in, int length) throws IOException { BaseMarshallerDelegate<A> marshallerDelegate = ctx.getMarshallerDelegate(clazz); A a; if (fd.getType() == Type.GROUP) { a = marshallerDelegate.unmarshall(fd, this, in); in.checkLastTagWas(WireFormat.makeTag(fd.getNumber(), WireFormat.WIRETYPE_END_GROUP)); } else if (fd.getType() == Type.MESSAGE) { if (length < 0) { length = in.readRawVarint32(); } int oldLimit = in.pushLimit(length); a = marshallerDelegate.unmarshall(fd, this, in); in.checkLastTagWas(0); in.popLimit(oldLimit); } else { throw new IllegalArgumentException( "Declared field type is not a message or an enum : " + fd.getFullName()); } return a; }
@Override public <E, C extends Collection<? super E>> C readCollection( String fieldName, C collection, Class<E> elementClass) throws IOException { final FieldDescriptor fd = messageContext.marshallerDelegate.getFieldByName(fieldName); checkFieldRead(fd, true); if (primitiveTypes.contains(fd.getType())) { readPrimitiveCollection(fd, (Collection<Object>) collection, elementClass); return collection; } // todo validate type is compatible with readCollection final int expectedTag = WireFormat.makeTag(fd.getNumber(), fd.getType().getWireType()); while (true) { Object o = messageContext.unknownFieldSet.consumeTag(expectedTag); if (o == null) { break; } byte[] byteArray = (byte[]) o; RawProtoStreamReader in = RawProtoStreamReaderImpl.newInstance(byteArray); collection.add(readNestedObject(fd, elementClass, in, byteArray.length)); } while (true) { int tag = messageContext.in.readTag(); if (tag == 0) { break; } if (tag == expectedTag) { collection.add(readNestedObject(fd, elementClass, messageContext.in, -1)); } else { messageContext.unknownFieldSet.readSingleField(tag, messageContext.in); } } return collection; }
public void testReadStringRequireUtf8() throws Exception { String lorem = "Lorem ipsum dolor sit amet "; StringBuilder builder = new StringBuilder(); for (int i = 0; i < 4096; i += lorem.length()) { builder.append(lorem); } lorem = builder.toString().substring(0, 4096); byte[] bytes = lorem.getBytes("UTF-8"); ByteString.Output rawOutput = ByteString.newOutput(); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length); int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); output.writeRawVarint32(tag); output.writeRawVarint32(bytes.length); output.writeRawBytes(bytes); output.flush(); CodedInputStream input = CodedInputStream.newInstance( new ByteArrayInputStream(rawOutput.toByteString().toByteArray())); assertEquals(tag, input.readTag()); String text = input.readStringRequireUtf8(); assertEquals(lorem, text); }
/** * Called by subclasses to parse an unknown field or an extension. * * @return {@code true} unless the tag is an end-group tag. */ @Override protected boolean parseUnknownField( final CodedInputStream input, final ExtensionRegistryLite extensionRegistry, final int tag) throws IOException { final FieldSet<ExtensionDescriptor> extensions = ((ExtendableMessage) internalGetResult()).extensions; final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(getDefaultInstanceForType(), fieldNumber); boolean unknown = false; boolean packed = false; if (extension == null) { unknown = true; // Unknown field. } else if (wireType == FieldSet.getWireFormatForFieldType( extension.descriptor.getLiteType(), false /* isPacked */)) { packed = false; // Normal, unpacked value. } else if (extension.descriptor.isRepeated && extension.descriptor.type.isPackable() && wireType == FieldSet.getWireFormatForFieldType( extension.descriptor.getLiteType(), true /* isPacked */)) { packed = true; // Packed value. } else { unknown = true; // Wrong wire type. } if (unknown) { // Unknown field or wrong wire type. Skip. return input.skipField(tag); } if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final Object value = extension.descriptor.getEnumType().findValueByNumber(rawValue); if (value == null) { // If the number isn't recognized as a valid value for this // enum, drop it (don't even add it to unknownFields). return true; } extensions.addRepeatedField(extension.descriptor, value); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = FieldSet.readPrimitiveField(input, extension.descriptor.getLiteType()); extensions.addRepeatedField(extension.descriptor, value); } } input.popLimit(limit); } else { final Object value; switch (extension.descriptor.getLiteJavaType()) { case MESSAGE: { MessageLite.Builder subBuilder = null; if (!extension.descriptor.isRepeated()) { MessageLite existingValue = (MessageLite) extensions.getField(extension.descriptor); if (existingValue != null) { subBuilder = existingValue.toBuilder(); } } if (subBuilder == null) { subBuilder = extension.messageDefaultInstance.newBuilderForType(); } if (extension.descriptor.getLiteType() == WireFormat.FieldType.GROUP) { input.readGroup(extension.getNumber(), subBuilder, extensionRegistry); } else { input.readMessage(subBuilder, extensionRegistry); } value = subBuilder.build(); break; } case ENUM: final int rawValue = input.readEnum(); value = extension.descriptor.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // drop it. if (value == null) { return true; } break; default: value = FieldSet.readPrimitiveField(input, extension.descriptor.getLiteType()); break; } if (extension.descriptor.isRepeated()) { extensions.addRepeatedField(extension.descriptor, value); } else { extensions.setField(extension.descriptor, value); } } return true; }
/** * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder, ExtensionRegistryLite, * Message.Builder)}, but parses a single field. Package-private because it is used by * GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @return {@code true} unless the tag is an end-group tag. */ @SuppressWarnings("unchecked") static boolean mergeFieldFrom( final CodedInputStream input, final UnknownFieldSet.Builder unknownFields, final ExtensionRegistryLite extensionRegistry, final Message.Builder builder, final int tag) throws IOException { final Descriptor type = builder.getDescriptorForType(); if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) { mergeMessageSetExtensionFromCodedStream(input, unknownFields, extensionRegistry, builder); return true; } final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final FieldDescriptor field; Message defaultInstance = null; if (type.isExtensionNumber(fieldNumber)) { // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { final ExtensionRegistry.ExtensionInfo extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, fieldNumber); if (extension == null) { field = null; } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; } } else { field = null; } } else { field = type.findFieldByNumber(fieldNumber); } if (field == null || wireType != FieldSet.getWireFormatForFieldType( field.getLiteType(), field.getOptions().getPacked())) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } if (field.getOptions().getPacked()) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final 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); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = FieldSet.readPrimitiveField(input, field.getLiteType()); builder.addRepeatedField(field, value); } } input.popLimit(limit); } else { final Object value; switch (field.getType()) { case GROUP: { final 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; } case MESSAGE: { final 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; } case ENUM: final 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; default: value = FieldSet.readPrimitiveField(input, field.getLiteType()); break; } if (field.isRepeated()) { builder.addRepeatedField(field, value); } else { builder.setField(field, value); } } return true; }
/** Compute the number of bytes that would be needed to encode a tag. */ public static int computeTagSize(int fieldNumber) { return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0)); }
/** Encode and write a tag. */ public void writeTag(int fieldNumber, int wireType) { writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType)); }
private void readPrimitiveCollection( FieldDescriptor fd, Collection<? super Object> collection, Class elementClass) throws IOException { final int expectedTag = WireFormat.makeTag(fd.getNumber(), fd.getType().getWireType()); Type type = fd.getType(); while (true) { Object o = messageContext.unknownFieldSet.consumeTag(expectedTag); if (o == null) { break; } collection.add( convertWireTypeToJavaType(type, o)); // todo check that (o.getClass() == elementClass) } while (true) { int tag = messageContext.in.readTag(); if (tag == 0) { break; } if (tag == expectedTag) { Object value; switch (type) { case DOUBLE: value = messageContext.in.readDouble(); break; case FLOAT: value = messageContext.in.readFloat(); break; case BOOL: value = messageContext.in.readBool(); break; case STRING: value = messageContext.in.readString(); break; case BYTES: value = messageContext.in.readByteArray(); break; case INT64: value = messageContext.in.readInt64(); break; case UINT64: value = messageContext.in.readUInt64(); break; case FIXED64: value = messageContext.in.readFixed64(); break; case SFIXED64: value = messageContext.in.readSFixed64(); break; case SINT64: value = messageContext.in.readSInt64(); break; case INT32: value = messageContext.in.readInt32(); break; case FIXED32: value = messageContext.in.readFixed32(); break; case UINT32: value = messageContext.in.readUInt32(); break; case SFIXED32: value = messageContext.in.readSFixed32(); break; case SINT32: value = messageContext.in.readSInt32(); break; default: throw new IllegalStateException("Unexpected field type : " + type); } collection.add(value); } else { messageContext.unknownFieldSet.readSingleField(tag, messageContext.in); } } }
private Object readPrimitive(String fieldName, JavaType javaType) throws IOException { final FieldDescriptor fd = messageContext.marshallerDelegate.getFieldByName(fieldName); final Type type = fd.getType(); if (type == Type.ENUM || type == Type.GROUP || type == Type.MESSAGE) { throw new IllegalArgumentException( "Declared field type is not a primitive : " + fd.getFullName()); } if (fd.getJavaType() != javaType) { throw new IllegalArgumentException( "Declared field type is not of the expected type : " + fd.getFullName()); } checkFieldRead(fd, false); final int expectedTag = WireFormat.makeTag(fd.getNumber(), type.getWireType()); Object o = messageContext.unknownFieldSet.consumeTag(expectedTag); if (o != null) { return convertWireTypeToJavaType(type, o); } RawProtoStreamReader in = messageContext.in; while (true) { int tag = in.readTag(); if (tag == 0) { break; } if (tag == expectedTag) { switch (type) { case DOUBLE: return in.readDouble(); case FLOAT: return in.readFloat(); case BOOL: return in.readBool(); case STRING: return in.readString(); case BYTES: return in.readByteArray(); case INT32: return in.readInt32(); case SFIXED32: return in.readSFixed32(); case FIXED32: return in.readFixed32(); case UINT32: return in.readUInt32(); case SINT32: return in.readSInt32(); case INT64: return in.readInt64(); case UINT64: return in.readUInt64(); case FIXED64: return in.readFixed64(); case SFIXED64: return in.readSFixed64(); case SINT64: return in.readSInt64(); default: throw new IOException("Unexpected field type : " + type); } } messageContext.unknownFieldSet.readSingleField(tag, in); } if (fd.hasDefaultValue()) { return fd.getDefaultValue(); } if (fd.isRequired()) { throw new IOException( "Field " + fd.getFullName() + " is required but is not present in the stream"); } return null; }
/** * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but parses a single field. * * <p>When {@code builder} is not null, the method will parse and merge the field into {@code * builder}. Otherwise, it will try to parse the field into {@code extensions}, when it's called * by the parsing constructor in generated classes. * * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @return {@code true} unless the tag is an end-group tag. */ static boolean mergeFieldFrom( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, Descriptor type, Message.Builder builder, FieldSet<FieldDescriptor> extensions, int tag) throws IOException { if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) { mergeMessageSetExtensionFromCodedStream( input, unknownFields, extensionRegistry, type, builder, extensions); return true; } final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final FieldDescriptor field; Message defaultInstance = null; if (type.isExtensionNumber(fieldNumber)) { // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { final ExtensionRegistry.ExtensionInfo extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, fieldNumber); if (extension == null) { field = null; } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; if (defaultInstance == null && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { throw new IllegalStateException( "Message-typed extension lacked default instance: " + field.getFullName()); } } } else { field = null; } } else if (builder != null) { field = type.findFieldByNumber(fieldNumber); } else { field = null; } boolean unknown = false; boolean packed = false; if (field == null) { unknown = true; // Unknown field. } else if (wireType == FieldSet.getWireFormatForFieldType(field.getLiteType(), false /* isPacked */)) { packed = false; } else if (field.isPackable() && wireType == FieldSet.getWireFormatForFieldType(field.getLiteType(), true /* isPacked */)) { packed = true; } else { unknown = true; // Unknown wire type. } if (unknown) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final 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; } addRepeatedField(builder, extensions, field, value); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = FieldSet.readPrimitiveField(input, field.getLiteType()); addRepeatedField(builder, extensions, field, value); } } input.popLimit(limit); } else { final Object value; switch (field.getType()) { case GROUP: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { mergeOriginalMessage(builder, extensions, field, subBuilder); } input.readGroup(field.getNumber(), subBuilder, extensionRegistry); value = subBuilder.buildPartial(); break; } case MESSAGE: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { mergeOriginalMessage(builder, extensions, field, subBuilder); } input.readMessage(subBuilder, extensionRegistry); value = subBuilder.buildPartial(); break; } case ENUM: final 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; default: value = FieldSet.readPrimitiveField(input, field.getLiteType()); break; } if (field.isRepeated()) { addRepeatedField(builder, extensions, field, value); } else { setField(builder, extensions, field, value); } } return true; }