Example #1
0
 /**
  * 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();
   }
 }
Example #2
0
 /**
  * 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();
   }
 }
Example #3
0
 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);
  }
Example #6
0
 /** 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;
 }
Example #7
0
 /** 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;
 }
Example #8
0
  /**
   * 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;
  }
Example #9
0
  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;
  }
Example #10
0
  /**
   * 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);
      }
    }
  }
Example #14
0
  /**
   * 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());
    }
  }
Example #15
0
  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;
  }
Example #18
0
  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);
  }
Example #19
0
    /**
     * 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;
    }
Example #20
0
    /**
     * 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;
    }
Example #21
0
 /** 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));
 }
Example #22
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;
    }