// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.protobuf;

import static com.google.protobuf.WireFormat.FIXED32_SIZE;
import static com.google.protobuf.WireFormat.FIXED64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT32_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import static java.lang.Math.max;

import com.google.protobuf.Utf8.UnpairedSurrogateException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.logging.Level;
import java.util.logging.Logger;

Encodes and writes protocol message fields.

This class contains two kinds of methods: methods that write specific protocol message constructs and field types (e.g. writeTag and writeInt32) and methods that write low-level values (e.g. writeRawVarint32 and writeRawBytes). If you are writing encoded protocol messages, you should use the former methods, but if you are writing some other format of your own design, use the latter.

This class is totally unsynchronized.

/** * Encodes and writes protocol message fields. * * <p>This class contains two kinds of methods: methods that write specific protocol message * constructs and field types (e.g. {@link #writeTag} and {@link #writeInt32}) and methods that * write low-level values (e.g. {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are * writing encoded protocol messages, you should use the former methods, but if you are writing some * other format of your own design, use the latter. * * <p>This class is totally unsynchronized. */
public abstract class CodedOutputStream extends ByteOutput { private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
Used to adapt to the experimental Writer interface.
/** Used to adapt to the experimental {@link Writer} interface. */
CodedOutputStreamWriter wrapper;
Deprecated:Use computeFixed32SizeNoTag(int) instead.
/** @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. */
@Deprecated public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
The buffer size used in newInstance(OutputStream).
/** The buffer size used in {@link #newInstance(OutputStream)}. */
public static final int DEFAULT_BUFFER_SIZE = 4096;
Returns the buffer size to efficiently write dataLength bytes to this CodedOutputStream. Used by AbstractMessageLite.
Returns:the buffer size to efficiently write dataLength bytes to this CodedOutputStream.
/** * Returns the buffer size to efficiently write dataLength bytes to this CodedOutputStream. Used * by AbstractMessageLite. * * @return the buffer size to efficiently write dataLength bytes to this CodedOutputStream. */
static int computePreferredBufferSize(int dataLength) { if (dataLength > DEFAULT_BUFFER_SIZE) { return DEFAULT_BUFFER_SIZE; } return dataLength; }
Create a new CodedOutputStream wrapping the given OutputStream.

NOTE: The provided OutputStream MUST NOT retain access or modify the provided byte arrays. Doing so may result in corrupted data, which would be difficult to debug.

/** * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}. * * <p>NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or modify * the provided byte arrays. Doing so may result in corrupted data, which would be difficult to * debug. */
public static CodedOutputStream newInstance(final OutputStream output) { return newInstance(output, DEFAULT_BUFFER_SIZE); }
Create a new CodedOutputStream wrapping the given OutputStream with a given buffer size.

NOTE: The provided OutputStream MUST NOT retain access or modify the provided byte arrays. Doing so may result in corrupted data, which would be difficult to debug.

/** * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given * buffer size. * * <p>NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or modify * the provided byte arrays. Doing so may result in corrupted data, which would be difficult to * debug. */
public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) { return new OutputStreamEncoder(output, bufferSize); }
Create a new CodedOutputStream that writes directly to the given byte array. If more bytes are written than fit in the array, OutOfSpaceException will be thrown. Writing directly to a flat array is faster than writing to an OutputStream. See also ByteString.newCodedBuilder.
/** * Create a new {@code CodedOutputStream} that writes directly to the given byte array. If more * bytes are written than fit in the array, {@link OutOfSpaceException} will be thrown. Writing * directly to a flat array is faster than writing to an {@code OutputStream}. See also {@link * ByteString#newCodedBuilder}. */
public static CodedOutputStream newInstance(final byte[] flatArray) { return newInstance(flatArray, 0, flatArray.length); }
Create a new CodedOutputStream that writes directly to the given byte array slice. If more bytes are written than fit in the slice, OutOfSpaceException will be thrown. Writing directly to a flat array is faster than writing to an OutputStream. See also ByteString.newCodedBuilder.
/** * Create a new {@code CodedOutputStream} that writes directly to the given byte array slice. If * more bytes are written than fit in the slice, {@link OutOfSpaceException} will be thrown. * Writing directly to a flat array is faster than writing to an {@code OutputStream}. See also * {@link ByteString#newCodedBuilder}. */
public static CodedOutputStream newInstance( final byte[] flatArray, final int offset, final int length) { return new ArrayEncoder(flatArray, offset, length); }
Create a new CodedOutputStream that writes to the given ByteBuffer.
/** Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. */
public static CodedOutputStream newInstance(ByteBuffer buffer) { if (buffer.hasArray()) { return new HeapNioEncoder(buffer); } if (buffer.isDirect() && !buffer.isReadOnly()) { return UnsafeDirectNioEncoder.isSupported() ? newUnsafeInstance(buffer) : newSafeInstance(buffer); } throw new IllegalArgumentException("ByteBuffer is read-only"); }
For testing purposes only.
/** For testing purposes only. */
static CodedOutputStream newUnsafeInstance(ByteBuffer buffer) { return new UnsafeDirectNioEncoder(buffer); }
For testing purposes only.
/** For testing purposes only. */
static CodedOutputStream newSafeInstance(ByteBuffer buffer) { return new SafeDirectNioEncoder(buffer); }
Configures serialization to be deterministic.

The deterministic serialization guarantees that for a given binary, equal (defined by the equals() methods in protos) messages will always be serialized to the same bytes. This implies:

  • repeated serialization of a message will return the same bytes
  • different processes of the same binary (which may be executing on different machines) will serialize equal messages to the same bytes.

Note the deterministic serialization is NOT canonical across languages; it is also unstable across different builds with schema changes due to unknown fields. Users who need canonical serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define their own canonicalization specification and implement the serializer using reflection APIs rather than relying on this API.

Once set, the serializer will: (Note this is an implementation detail and may subject to change in the future)

  • sort map entries by keys in lexicographical order or numerical order. Note: For string keys, the order is based on comparing the Unicode value of each character in the strings. The order may be different from the deterministic serialization in other languages where maps are sorted on the lexicographical order of the UTF8 encoded keys.
/** * Configures serialization to be deterministic. * * <p>The deterministic serialization guarantees that for a given binary, equal (defined by the * {@code equals()} methods in protos) messages will always be serialized to the same bytes. This * implies: * * <ul> * <li>repeated serialization of a message will return the same bytes * <li>different processes of the same binary (which may be executing on different machines) * will serialize equal messages to the same bytes. * </ul> * * <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable * across different builds with schema changes due to unknown fields. Users who need canonical * serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define * their own canonicalization specification and implement the serializer using reflection APIs * rather than relying on this API. * * <p>Once set, the serializer will: (Note this is an implementation detail and may subject to * change in the future) * * <ul> * <li>sort map entries by keys in lexicographical order or numerical order. Note: For string * keys, the order is based on comparing the Unicode value of each character in the strings. * The order may be different from the deterministic serialization in other languages where * maps are sorted on the lexicographical order of the UTF8 encoded keys. * </ul> */
public void useDeterministicSerialization() { serializationDeterministic = true; } boolean isSerializationDeterministic() { return serializationDeterministic; } private boolean serializationDeterministic;
Create a new CodedOutputStream that writes to the given ByteBuffer.
Deprecated:the size parameter is no longer used since use of an internal buffer is useless (and wasteful) when writing to a ByteBuffer. Use newInstance(ByteBuffer) instead.
/** * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. * * @deprecated the size parameter is no longer used since use of an internal buffer is useless * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)} * instead. */
@Deprecated public static CodedOutputStream newInstance( ByteBuffer byteBuffer, @SuppressWarnings("unused") int unused) { return newInstance(byteBuffer); }
Create a new CodedOutputStream that writes to the provided ByteOutput.

NOTE: The ByteOutput MUST NOT modify the provided buffers. Doing so may result in corrupted data, which would be difficult to debug.

Params:
  • byteOutput – the output target for encoded bytes.
  • bufferSize – the size of the internal scratch buffer to be used for string encoding. Setting this to 0 will disable buffering, requiring an allocation for each encoded string.
/** * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}. * * <p>NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing so * may result in corrupted data, which would be difficult to debug. * * @param byteOutput the output target for encoded bytes. * @param bufferSize the size of the internal scratch buffer to be used for string encoding. * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded * string. */
static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) { if (bufferSize < 0) { throw new IllegalArgumentException("bufferSize must be positive"); } return new ByteOutputEncoder(byteOutput, bufferSize); } // Disallow construction outside of this class. private CodedOutputStream() {} // -----------------------------------------------------------------
Encode and write a tag.
/** Encode and write a tag. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeTag(int fieldNumber, int wireType) throws IOException;
Write an int32 field, including tag, to the stream.
/** Write an {@code int32} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeInt32(int fieldNumber, int value) throws IOException;
Write a uint32 field, including tag, to the stream.
/** Write a {@code uint32} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeUInt32(int fieldNumber, int value) throws IOException;
Write a sint32 field, including tag, to the stream.
/** Write a {@code sint32} field, including tag, to the stream. */
public final void writeSInt32(final int fieldNumber, final int value) throws IOException { writeUInt32(fieldNumber, encodeZigZag32(value)); }
Write a fixed32 field, including tag, to the stream.
/** Write a {@code fixed32} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeFixed32(int fieldNumber, int value) throws IOException;
Write an sfixed32 field, including tag, to the stream.
/** Write an {@code sfixed32} field, including tag, to the stream. */
public final void writeSFixed32(final int fieldNumber, final int value) throws IOException { writeFixed32(fieldNumber, value); }
Write an int64 field, including tag, to the stream.
/** Write an {@code int64} field, including tag, to the stream. */
public final void writeInt64(final int fieldNumber, final long value) throws IOException { writeUInt64(fieldNumber, value); }
Write a uint64 field, including tag, to the stream.
/** Write a {@code uint64} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeUInt64(int fieldNumber, long value) throws IOException;
Write an sint64 field, including tag, to the stream.
/** Write an {@code sint64} field, including tag, to the stream. */
public final void writeSInt64(final int fieldNumber, final long value) throws IOException { writeUInt64(fieldNumber, encodeZigZag64(value)); }
Write a fixed64 field, including tag, to the stream.
/** Write a {@code fixed64} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeFixed64(int fieldNumber, long value) throws IOException;
Write an sfixed64 field, including tag, to the stream.
/** Write an {@code sfixed64} field, including tag, to the stream. */
public final void writeSFixed64(final int fieldNumber, final long value) throws IOException { writeFixed64(fieldNumber, value); }
Write a float field, including tag, to the stream.
/** Write a {@code float} field, including tag, to the stream. */
public final void writeFloat(final int fieldNumber, final float value) throws IOException { writeFixed32(fieldNumber, Float.floatToRawIntBits(value)); }
Write a double field, including tag, to the stream.
/** Write a {@code double} field, including tag, to the stream. */
public final void writeDouble(final int fieldNumber, final double value) throws IOException { writeFixed64(fieldNumber, Double.doubleToRawLongBits(value)); }
Write a bool field, including tag, to the stream.
/** Write a {@code bool} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
Write an enum field, including tag, to the stream. The provided value is the numeric value used to represent the enum value on the wire (not the enum ordinal value).
/** * Write an enum field, including tag, to the stream. The provided value is the numeric value used * to represent the enum value on the wire (not the enum ordinal value). */
public final void writeEnum(final int fieldNumber, final int value) throws IOException { writeInt32(fieldNumber, value); }
Write a string field, including tag, to the stream.
/** Write a {@code string} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeString(int fieldNumber, String value) throws IOException;
Write a bytes field, including tag, to the stream.
/** Write a {@code bytes} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException;
Write a bytes field, including tag, to the stream.
/** Write a {@code bytes} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException;
Write a bytes field, including tag, to the stream.
/** Write a {@code bytes} field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length) throws IOException;
Write a bytes field, including tag, to the stream. This method will write all content of the ByteBuffer regardless of the current position and limit (i.e., the number of bytes to be written is value.capacity(), not value.remaining()). Furthermore, this method doesn't alter the state of the passed-in ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If you only want to write the remaining bytes of a ByteBuffer, you can call writeByteBuffer(fieldNumber, byteBuffer.slice()).
/** * Write a {@code bytes} field, including tag, to the stream. This method will write all content * of the ByteBuffer regardless of the current position and limit (i.e., the number of bytes to be * written is value.capacity(), not value.remaining()). Furthermore, this method doesn't alter the * state of the passed-in ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If * you only want to write the remaining bytes of a ByteBuffer, you can call {@code * writeByteBuffer(fieldNumber, byteBuffer.slice())}. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
Write a single byte.
/** Write a single byte. */
public final void writeRawByte(final byte value) throws IOException { write(value); }
Write a single byte, represented by an integer value.
/** Write a single byte, represented by an integer value. */
public final void writeRawByte(final int value) throws IOException { write((byte) value); }
Write an array of bytes.
/** Write an array of bytes. */
public final void writeRawBytes(final byte[] value) throws IOException { write(value, 0, value.length); }
Write part of an array of bytes.
/** Write part of an array of bytes. */
public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException { write(value, offset, length); }
Write a byte string.
/** Write a byte string. */
public final void writeRawBytes(final ByteString value) throws IOException { value.writeTo(this); }
Write a ByteBuffer. This method will write all content of the ByteBuffer regardless of the current position and limit (i.e., the number of bytes to be written is value.capacity(), not value.remaining()). Furthermore, this method doesn't alter the state of the passed-in ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If you only want to write the remaining bytes of a ByteBuffer, you can call writeRawBytes(byteBuffer.slice()).
/** * Write a ByteBuffer. This method will write all content of the ByteBuffer regardless of the * current position and limit (i.e., the number of bytes to be written is value.capacity(), not * value.remaining()). Furthermore, this method doesn't alter the state of the passed-in * ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If you only want to write * the remaining bytes of a ByteBuffer, you can call {@code writeRawBytes(byteBuffer.slice())}. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
Write an embedded message field, including tag, to the stream.
/** Write an embedded message field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeMessage(final int fieldNumber, final MessageLite value) throws IOException;
Write an embedded message field, including tag, to the stream.
/** Write an embedded message field, including tag, to the stream. */
// Abstract to avoid overhead of additional virtual method calls. abstract void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) throws IOException;
Write a MessageSet extension field to the stream. For historical reasons, the wire format differs from normal fields.
/** * Write a MessageSet extension field to the stream. For historical reasons, the wire format * differs from normal fields. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value) throws IOException;
Write an unparsed MessageSet extension field to the stream. For historical reasons, the wire format differs from normal fields.
/** * Write an unparsed MessageSet extension field to the stream. For historical reasons, the wire * format differs from normal fields. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) throws IOException; // -----------------------------------------------------------------
Write an int32 field to the stream.
/** Write an {@code int32} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeInt32NoTag(final int value) throws IOException;
Write a uint32 field to the stream.
/** Write a {@code uint32} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeUInt32NoTag(int value) throws IOException;
Write a sint32 field to the stream.
/** Write a {@code sint32} field to the stream. */
public final void writeSInt32NoTag(final int value) throws IOException { writeUInt32NoTag(encodeZigZag32(value)); }
Write a fixed32 field to the stream.
/** Write a {@code fixed32} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeFixed32NoTag(int value) throws IOException;
Write a sfixed32 field to the stream.
/** Write a {@code sfixed32} field to the stream. */
public final void writeSFixed32NoTag(final int value) throws IOException { writeFixed32NoTag(value); }
Write an int64 field to the stream.
/** Write an {@code int64} field to the stream. */
public final void writeInt64NoTag(final long value) throws IOException { writeUInt64NoTag(value); }
Write a uint64 field to the stream.
/** Write a {@code uint64} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeUInt64NoTag(long value) throws IOException;
Write a sint64 field to the stream.
/** Write a {@code sint64} field to the stream. */
public final void writeSInt64NoTag(final long value) throws IOException { writeUInt64NoTag(encodeZigZag64(value)); }
Write a fixed64 field to the stream.
/** Write a {@code fixed64} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeFixed64NoTag(long value) throws IOException;
Write a sfixed64 field to the stream.
/** Write a {@code sfixed64} field to the stream. */
public final void writeSFixed64NoTag(final long value) throws IOException { writeFixed64NoTag(value); }
Write a float field to the stream.
/** Write a {@code float} field to the stream. */
public final void writeFloatNoTag(final float value) throws IOException { writeFixed32NoTag(Float.floatToRawIntBits(value)); }
Write a double field to the stream.
/** Write a {@code double} field to the stream. */
public final void writeDoubleNoTag(final double value) throws IOException { writeFixed64NoTag(Double.doubleToRawLongBits(value)); }
Write a bool field to the stream.
/** Write a {@code bool} field to the stream. */
public final void writeBoolNoTag(final boolean value) throws IOException { write((byte) (value ? 1 : 0)); }
Write an enum field to the stream. The provided value is the numeric value used to represent the enum value on the wire (not the enum ordinal value).
/** * Write an enum field to the stream. The provided value is the numeric value used to represent * the enum value on the wire (not the enum ordinal value). */
public final void writeEnumNoTag(final int value) throws IOException { writeInt32NoTag(value); }
Write a string field to the stream.
/** Write a {@code string} field to the stream. */
// TODO(dweis): Document behavior on ill-formed UTF-16 input. // Abstract to avoid overhead of additional virtual method calls. public abstract void writeStringNoTag(String value) throws IOException;
Write a bytes field to the stream.
/** Write a {@code bytes} field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeBytesNoTag(final ByteString value) throws IOException;
Write a bytes field to the stream.
/** Write a {@code bytes} field to the stream. */
public final void writeByteArrayNoTag(final byte[] value) throws IOException { writeByteArrayNoTag(value, 0, value.length); }
Write an embedded message field to the stream.
/** Write an embedded message field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
Write an embedded message field to the stream.
/** Write an embedded message field to the stream. */
// Abstract to avoid overhead of additional virtual method calls. abstract void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException; // ================================================================= @ExperimentalApi @Override public abstract void write(byte value) throws IOException; @ExperimentalApi @Override public abstract void write(byte[] value, int offset, int length) throws IOException; @ExperimentalApi @Override public abstract void writeLazy(byte[] value, int offset, int length) throws IOException; @Override public abstract void write(ByteBuffer value) throws IOException; @ExperimentalApi @Override public abstract void writeLazy(ByteBuffer value) throws IOException; // ================================================================= // =================================================================
Compute the number of bytes that would be needed to encode an int32 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code int32} field, including * tag. */
public static int computeInt32Size(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a uint32 field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code uint32} field, including * tag. */
public static int computeUInt32Size(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode an sint32 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code sint32} field, including * tag. */
public static int computeSInt32Size(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a fixed32 field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code fixed32} field, including * tag. */
public static int computeFixed32Size(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode an sfixed32 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code sfixed32} field, including * tag. */
public static int computeSFixed32Size(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode an int64 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code int64} field, including * tag. */
public static int computeInt64Size(final int fieldNumber, final long value) { return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a uint64 field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code uint64} field, including * tag. */
public static int computeUInt64Size(final int fieldNumber, final long value) { return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode an sint64 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code sint64} field, including * tag. */
public static int computeSInt64Size(final int fieldNumber, final long value) { return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a fixed64 field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code fixed64} field, including * tag. */
public static int computeFixed64Size(final int fieldNumber, final long value) { return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode an sfixed64 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code sfixed64} field, including * tag. */
public static int computeSFixed64Size(final int fieldNumber, final long value) { return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a float field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code float} field, including * tag. */
public static int computeFloatSize(final int fieldNumber, final float value) { return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a double field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code double} field, including * tag. */
public static int computeDoubleSize(final int fieldNumber, final double value) { return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a bool field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code bool} field, including tag. */
public static int computeBoolSize(final int fieldNumber, final boolean value) { return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); }
Compute the number of bytes that would be needed to encode an enum field, including tag. The provided value is the numeric value used to represent the enum value on the wire (not the enum ordinal value).
/** * Compute the number of bytes that would be needed to encode an enum field, including tag. The * provided value is the numeric value used to represent the enum value on the wire (not the enum * ordinal value). */
public static int computeEnumSize(final int fieldNumber, final int value) { return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a string field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code string} field, including * tag. */
public static int computeStringSize(final int fieldNumber, final String value) { return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a bytes field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code bytes} field, including * tag. */
public static int computeBytesSize(final int fieldNumber, final ByteString value) { return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a bytes field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code bytes} field, including * tag. */
public static int computeByteArraySize(final int fieldNumber, final byte[] value) { return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value); }
Compute the number of bytes that would be needed to encode a bytes field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code bytes} field, including * tag. */
public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) { return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value); }
Compute the number of bytes that would be needed to encode an embedded message in lazy field, including tag.
/** * Compute the number of bytes that would be needed to encode an embedded message in lazy field, * including tag. */
public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) { return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value); }
Compute the number of bytes that would be needed to encode an embedded message field, including tag.
/** * Compute the number of bytes that would be needed to encode an embedded message field, including * tag. */
public static int computeMessageSize(final int fieldNumber, final MessageLite value) { return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); }
Compute the number of bytes that would be needed to encode an embedded message field, including tag.
/** * Compute the number of bytes that would be needed to encode an embedded message field, including * tag. */
static int computeMessageSize( final int fieldNumber, final MessageLite value, final Schema schema) { return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value, schema); }
Compute the number of bytes that would be needed to encode a MessageSet extension to the stream. For historical reasons, the wire format differs from normal fields.
/** * Compute the number of bytes that would be needed to encode a MessageSet extension to the * stream. For historical reasons, the wire format differs from normal fields. */
public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) { return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value); }
Compute the number of bytes that would be needed to encode an unparsed MessageSet extension field to the stream. For historical reasons, the wire format differs from normal fields.
/** * Compute the number of bytes that would be needed to encode an unparsed MessageSet extension * field to the stream. For historical reasons, the wire format differs from normal fields. */
public static int computeRawMessageSetExtensionSize( final int fieldNumber, final ByteString value) { return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value); }
Compute the number of bytes that would be needed to encode an lazily parsed MessageSet extension field to the stream. For historical reasons, the wire format differs from normal fields.
/** * Compute the number of bytes that would be needed to encode an lazily parsed MessageSet * extension field to the stream. For historical reasons, the wire format differs from normal * fields. */
public static int computeLazyFieldMessageSetExtensionSize( final int fieldNumber, final LazyFieldLite value) { return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value); } // -----------------------------------------------------------------
Compute the number of bytes that would be needed to encode a tag.
/** Compute the number of bytes that would be needed to encode a tag. */
public static int computeTagSize(final int fieldNumber) { return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0)); }
Compute the number of bytes that would be needed to encode an int32 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code int32} field, including * tag. */
public static int computeInt32SizeNoTag(final int value) { if (value >= 0) { return computeUInt32SizeNoTag(value); } else { // Must sign-extend. return MAX_VARINT_SIZE; } }
Compute the number of bytes that would be needed to encode a uint32 field.
/** Compute the number of bytes that would be needed to encode a {@code uint32} field. */
public static int computeUInt32SizeNoTag(final int value) { if ((value & (~0 << 7)) == 0) { return 1; } if ((value & (~0 << 14)) == 0) { return 2; } if ((value & (~0 << 21)) == 0) { return 3; } if ((value & (~0 << 28)) == 0) { return 4; } return 5; }
Compute the number of bytes that would be needed to encode an sint32 field.
/** Compute the number of bytes that would be needed to encode an {@code sint32} field. */
public static int computeSInt32SizeNoTag(final int value) { return computeUInt32SizeNoTag(encodeZigZag32(value)); }
Compute the number of bytes that would be needed to encode a fixed32 field.
/** Compute the number of bytes that would be needed to encode a {@code fixed32} field. */
public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { return FIXED32_SIZE; }
Compute the number of bytes that would be needed to encode an sfixed32 field.
/** Compute the number of bytes that would be needed to encode an {@code sfixed32} field. */
public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { return FIXED32_SIZE; }
Compute the number of bytes that would be needed to encode an int64 field, including tag.
/** * Compute the number of bytes that would be needed to encode an {@code int64} field, including * tag. */
public static int computeInt64SizeNoTag(final long value) { return computeUInt64SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a uint64 field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code uint64} field, including * tag. */
public static int computeUInt64SizeNoTag(long value) { // handle two popular special cases up front ... if ((value & (~0L << 7)) == 0L) { return 1; } if (value < 0L) { return 10; } // ... leaving us with 8 remaining, which we can divide and conquer int n = 2; if ((value & (~0L << 35)) != 0L) { n += 4; value >>>= 28; } if ((value & (~0L << 21)) != 0L) { n += 2; value >>>= 14; } if ((value & (~0L << 14)) != 0L) { n += 1; } return n; }
Compute the number of bytes that would be needed to encode an sint64 field.
/** Compute the number of bytes that would be needed to encode an {@code sint64} field. */
public static int computeSInt64SizeNoTag(final long value) { return computeUInt64SizeNoTag(encodeZigZag64(value)); }
Compute the number of bytes that would be needed to encode a fixed64 field.
/** Compute the number of bytes that would be needed to encode a {@code fixed64} field. */
public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { return FIXED64_SIZE; }
Compute the number of bytes that would be needed to encode an sfixed64 field.
/** Compute the number of bytes that would be needed to encode an {@code sfixed64} field. */
public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { return FIXED64_SIZE; }
Compute the number of bytes that would be needed to encode a float field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code float} field, including * tag. */
public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) { return FIXED32_SIZE; }
Compute the number of bytes that would be needed to encode a double field, including tag.
/** * Compute the number of bytes that would be needed to encode a {@code double} field, including * tag. */
public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) { return FIXED64_SIZE; }
Compute the number of bytes that would be needed to encode a bool field.
/** Compute the number of bytes that would be needed to encode a {@code bool} field. */
public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) { return 1; }
Compute the number of bytes that would be needed to encode an enum field. The provided value is the numeric value used to represent the enum value on the wire (not the enum ordinal value).
/** * Compute the number of bytes that would be needed to encode an enum field. The provided value is * the numeric value used to represent the enum value on the wire (not the enum ordinal value). */
public static int computeEnumSizeNoTag(final int value) { return computeInt32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a string field.
/** Compute the number of bytes that would be needed to encode a {@code string} field. */
public static int computeStringSizeNoTag(final String value) { int length; try { length = Utf8.encodedLength(value); } catch (UnpairedSurrogateException e) { // TODO(dweis): Consider using nio Charset methods instead. final byte[] bytes = value.getBytes(Internal.UTF_8); length = bytes.length; } return computeLengthDelimitedFieldSize(length); }
Compute the number of bytes that would be needed to encode an embedded message stored in lazy field.
/** * Compute the number of bytes that would be needed to encode an embedded message stored in lazy * field. */
public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) { return computeLengthDelimitedFieldSize(value.getSerializedSize()); }
Compute the number of bytes that would be needed to encode a bytes field.
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
public static int computeBytesSizeNoTag(final ByteString value) { return computeLengthDelimitedFieldSize(value.size()); }
Compute the number of bytes that would be needed to encode a bytes field.
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
public static int computeByteArraySizeNoTag(final byte[] value) { return computeLengthDelimitedFieldSize(value.length); }
Compute the number of bytes that would be needed to encode a bytes field.
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
public static int computeByteBufferSizeNoTag(final ByteBuffer value) { return computeLengthDelimitedFieldSize(value.capacity()); }
Compute the number of bytes that would be needed to encode an embedded message field.
/** Compute the number of bytes that would be needed to encode an embedded message field. */
public static int computeMessageSizeNoTag(final MessageLite value) { return computeLengthDelimitedFieldSize(value.getSerializedSize()); }
Compute the number of bytes that would be needed to encode an embedded message field.
/** Compute the number of bytes that would be needed to encode an embedded message field. */
static int computeMessageSizeNoTag(final MessageLite value, final Schema schema) { return computeLengthDelimitedFieldSize(((AbstractMessageLite) value).getSerializedSize(schema)); } static int computeLengthDelimitedFieldSize(int fieldLength) { return computeUInt32SizeNoTag(fieldLength) + fieldLength; }
Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into values that can be efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits to be varint encoded, thus always taking 10 bytes on the wire.)
Params:
  • n – A signed 32-bit integer.
Returns:An unsigned 32-bit integer, stored in a signed int because Java has no explicit unsigned support.
/** * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into values that can be * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits * to be varint encoded, thus always taking 10 bytes on the wire.) * * @param n A signed 32-bit integer. * @return An unsigned 32-bit integer, stored in a signed int because Java has no explicit * unsigned support. */
public static int encodeZigZag32(final int n) { // Note: the right-shift must be arithmetic return (n << 1) ^ (n >> 31); }
Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits to be varint encoded, thus always taking 10 bytes on the wire.)
Params:
  • n – A signed 64-bit integer.
Returns:An unsigned 64-bit integer, stored in a signed int because Java has no explicit unsigned support.
/** * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits * to be varint encoded, thus always taking 10 bytes on the wire.) * * @param n A signed 64-bit integer. * @return An unsigned 64-bit integer, stored in a signed int because Java has no explicit * unsigned support. */
public static long encodeZigZag64(final long n) { // Note: the right-shift must be arithmetic return (n << 1) ^ (n >> 63); } // =================================================================
Flushes the stream and forces any buffered bytes to be written. This does not flush the underlying OutputStream.
/** * Flushes the stream and forces any buffered bytes to be written. This does not flush the * underlying OutputStream. */
public abstract void flush() throws IOException;
If writing to a flat array, return the space left in the array. Otherwise, throws UnsupportedOperationException.
/** * If writing to a flat array, return the space left in the array. Otherwise, throws {@code * UnsupportedOperationException}. */
public abstract int spaceLeft();
Verifies that spaceLeft() returns zero. It's common to create a byte array that is exactly big enough to hold a message, then write to it with a CodedOutputStream. Calling checkNoSpaceLeft() after writing verifies that the message was actually as big as expected, which can help catch bugs.
/** * Verifies that {@link #spaceLeft()} returns zero. It's common to create a byte array that is * exactly big enough to hold a message, then write to it with a {@code CodedOutputStream}. * Calling {@code checkNoSpaceLeft()} after writing verifies that the message was actually as big * as expected, which can help catch bugs. */
public final void checkNoSpaceLeft() { if (spaceLeft() != 0) { throw new IllegalStateException("Did not write as much data as expected."); } }
If you create a CodedOutputStream around a simple flat array, you must not attempt to write more bytes than the array has space. Otherwise, this exception will be thrown.
/** * If you create a CodedOutputStream around a simple flat array, you must not attempt to write * more bytes than the array has space. Otherwise, this exception will be thrown. */
public static class OutOfSpaceException extends IOException { private static final long serialVersionUID = -6947486886997889499L; private static final String MESSAGE = "CodedOutputStream was writing to a flat byte array and ran out of space."; OutOfSpaceException() { super(MESSAGE); } OutOfSpaceException(String explanationMessage) { super(MESSAGE + ": " + explanationMessage); } OutOfSpaceException(Throwable cause) { super(MESSAGE, cause); } OutOfSpaceException(String explanationMessage, Throwable cause) { super(MESSAGE + ": " + explanationMessage, cause); } }
Get the total number of bytes successfully written to this stream. The returned value is not guaranteed to be accurate if exceptions have been found in the middle of writing.
/** * Get the total number of bytes successfully written to this stream. The returned value is not * guaranteed to be accurate if exceptions have been found in the middle of writing. */
public abstract int getTotalBytesWritten(); // =================================================================
Write a bytes field to the stream. Visible for testing.
/** Write a {@code bytes} field to the stream. Visible for testing. */
abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length) throws IOException; final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause) throws IOException { logger.log( Level.WARNING, "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause); // 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. // TODO(dweis): Consider using nio Charset methods instead. final byte[] bytes = value.getBytes(Internal.UTF_8); try { writeUInt32NoTag(bytes.length); writeLazy(bytes, 0, bytes.length); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } catch (OutOfSpaceException e) { throw e; } } // =================================================================
Write a group field, including tag, to the stream.
Deprecated:groups are deprecated.
/** * Write a {@code group} field, including tag, to the stream. * * @deprecated groups are deprecated. */
@Deprecated public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); writeGroupNoTag(value); writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); }
Write a group field, including tag, to the stream.
Deprecated:groups are deprecated.
/** * Write a {@code group} field, including tag, to the stream. * * @deprecated groups are deprecated. */
@Deprecated final void writeGroup(final int fieldNumber, final MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); writeGroupNoTag(value, schema); writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); }
Write a group field to the stream.
Deprecated:groups are deprecated.
/** * Write a {@code group} field to the stream. * * @deprecated groups are deprecated. */
@Deprecated public final void writeGroupNoTag(final MessageLite value) throws IOException { value.writeTo(this); }
Write a group field to the stream.
Deprecated:groups are deprecated.
/** * Write a {@code group} field to the stream. * * @deprecated groups are deprecated. */
@Deprecated final void writeGroupNoTag(final MessageLite value, Schema schema) throws IOException { schema.writeTo(value, wrapper); }
Compute the number of bytes that would be needed to encode a group field, including tag.
Deprecated:groups are deprecated.
/** * Compute the number of bytes that would be needed to encode a {@code group} field, including * tag. * * @deprecated groups are deprecated. */
@Deprecated public static int computeGroupSize(final int fieldNumber, final MessageLite value) { return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); }
Compute the number of bytes that would be needed to encode a group field, including tag.
Deprecated:groups are deprecated.
/** * Compute the number of bytes that would be needed to encode a {@code group} field, including * tag. * * @deprecated groups are deprecated. */
@Deprecated static int computeGroupSize(final int fieldNumber, final MessageLite value, Schema schema) { return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value, schema); }
Compute the number of bytes that would be needed to encode a group field.
/** Compute the number of bytes that would be needed to encode a {@code group} field. */
@Deprecated public static int computeGroupSizeNoTag(final MessageLite value) { return value.getSerializedSize(); }
Compute the number of bytes that would be needed to encode a group field.
/** Compute the number of bytes that would be needed to encode a {@code group} field. */
@Deprecated static int computeGroupSizeNoTag(final MessageLite value, Schema schema) { return ((AbstractMessageLite) value).getSerializedSize(schema); }
Encode and write a varint. value is treated as unsigned, so it won't be sign-extended if negative.
Deprecated:use writeUInt32NoTag instead.
/** * Encode and write a varint. {@code value} is treated as unsigned, so it won't be sign-extended * if negative. * * @deprecated use {@link #writeUInt32NoTag} instead. */
@Deprecated public final void writeRawVarint32(int value) throws IOException { writeUInt32NoTag(value); }
Encode and write a varint.
Deprecated:use writeUInt64NoTag instead.
/** * Encode and write a varint. * * @deprecated use {@link #writeUInt64NoTag} instead. */
@Deprecated public final void writeRawVarint64(long value) throws IOException { writeUInt64NoTag(value); }
Compute the number of bytes that would be needed to encode a varint. value is treated as unsigned, so it won't be sign-extended if negative.
Deprecated:use computeUInt32SizeNoTag(int) instead.
/** * Compute the number of bytes that would be needed to encode a varint. {@code value} is treated * as unsigned, so it won't be sign-extended if negative. * * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead. */
@Deprecated public static int computeRawVarint32Size(final int value) { return computeUInt32SizeNoTag(value); }
Compute the number of bytes that would be needed to encode a varint.
Deprecated:use computeUInt64SizeNoTag(long) instead.
/** * Compute the number of bytes that would be needed to encode a varint. * * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead. */
@Deprecated public static int computeRawVarint64Size(long value) { return computeUInt64SizeNoTag(value); }
Write a little-endian 32-bit integer.
Deprecated:Use writeFixed32NoTag instead.
/** * Write a little-endian 32-bit integer. * * @deprecated Use {@link #writeFixed32NoTag} instead. */
@Deprecated public final void writeRawLittleEndian32(final int value) throws IOException { writeFixed32NoTag(value); }
Write a little-endian 64-bit integer.
Deprecated:Use writeFixed64NoTag instead.
/** * Write a little-endian 64-bit integer. * * @deprecated Use {@link #writeFixed64NoTag} instead. */
@Deprecated public final void writeRawLittleEndian64(final long value) throws IOException { writeFixed64NoTag(value); } // =================================================================
A CodedOutputStream that writes directly to a byte array.
/** A {@link CodedOutputStream} that writes directly to a byte array. */
private static class ArrayEncoder extends CodedOutputStream { private final byte[] buffer; private final int offset; private final int limit; private int position; ArrayEncoder(byte[] buffer, int offset, int length) { if (buffer == null) { throw new NullPointerException("buffer"); } if ((offset | length | (buffer.length - (offset + length))) < 0) { throw new IllegalArgumentException( String.format( "Array range is invalid. Buffer.length=%d, offset=%d, length=%d", buffer.length, offset, length)); } this.buffer = buffer; this.offset = offset; position = offset; limit = offset + length; } @Override public final void writeTag(final int fieldNumber, final int wireType) throws IOException { writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); } @Override public final void writeInt32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeInt32NoTag(value); } @Override public final void writeUInt32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt32NoTag(value); } @Override public final void writeFixed32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeFixed32NoTag(value); } @Override public final void writeUInt64(final int fieldNumber, final long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt64NoTag(value); } @Override public final void writeFixed64(final int fieldNumber, final long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeFixed64NoTag(value); } @Override public final void writeBool(final int fieldNumber, final boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); write((byte) (value ? 1 : 0)); } @Override public final void writeString(final int fieldNumber, final String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } @Override public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } @Override public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { writeByteArray(fieldNumber, value, 0, value.length); } @Override public final void writeByteArray( final int fieldNumber, final byte[] value, final int offset, final int length) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @Override public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(value.capacity()); writeRawBytes(value); } @Override public final void writeBytesNoTag(final ByteString value) throws IOException { writeUInt32NoTag(value.size()); value.writeTo(this); } @Override public final void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { writeUInt32NoTag(length); write(value, offset, length); } @Override public final void writeRawBytes(final ByteBuffer value) throws IOException { if (value.hasArray()) { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); duplicated.clear(); write(duplicated); } } @Override public final void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value); } @Override final void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public final void writeMessageNoTag(final MessageLite value) throws IOException { writeUInt32NoTag(value.getSerializedSize()); value.writeTo(this); } @Override final void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public final void write(byte value) throws IOException { try { buffer[position++] = value; } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e); } } @Override public final void writeInt32NoTag(int value) throws IOException { if (value >= 0) { writeUInt32NoTag(value); } else { // Must sign-extend. writeUInt64NoTag(value); } } @Override public final void writeUInt32NoTag(int value) throws IOException { if (HAS_UNSAFE_ARRAY_OPERATIONS && !Android.isOnAndroidDevice() && spaceLeft() >= MAX_VARINT32_SIZE) { if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); return; } UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80)); value >>>= 7; if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); return; } UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80)); value >>>= 7; if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); return; } UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80)); value >>>= 7; if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); return; } UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80)); value >>>= 7; UnsafeUtil.putByte(buffer, position++, (byte) value); } else { try { while (true) { if ((value & ~0x7F) == 0) { buffer[position++] = (byte) value; return; } else { buffer[position++] = (byte) ((value & 0x7F) | 0x80); value >>>= 7; } } } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e); } } } @Override public final void writeFixed32NoTag(int value) throws IOException { try { buffer[position++] = (byte) (value & 0xFF); buffer[position++] = (byte) ((value >> 8) & 0xFF); buffer[position++] = (byte) ((value >> 16) & 0xFF); buffer[position++] = (byte) ((value >> 24) & 0xFF); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e); } } @Override public final void writeUInt64NoTag(long value) throws IOException { if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { while (true) { if ((value & ~0x7FL) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); return; } else { UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80)); value >>>= 7; } } } else { try { while (true) { if ((value & ~0x7FL) == 0) { buffer[position++] = (byte) value; return; } else { buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); value >>>= 7; } } } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e); } } } @Override public final void writeFixed64NoTag(long value) throws IOException { try { buffer[position++] = (byte) ((int) (value) & 0xFF); buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e); } } @Override public final void write(byte[] value, int offset, int length) throws IOException { try { System.arraycopy(value, offset, buffer, position, length); position += length; } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e); } } @Override public final void writeLazy(byte[] value, int offset, int length) throws IOException { write(value, offset, length); } @Override public final void write(ByteBuffer value) throws IOException { final int length = value.remaining(); try { value.get(buffer, position, length); position += length; } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e); } } @Override public final void writeLazy(ByteBuffer value) throws IOException { write(value); } @Override public final void writeStringNoTag(String value) throws IOException { final int oldPosition = position; try { // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), // and at most 3 times of it. We take advantage of this in both branches below. final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); if (minLengthVarIntSize == maxLengthVarIntSize) { position = oldPosition + minLengthVarIntSize; int newPosition = Utf8.encode(value, buffer, position, spaceLeft()); // Since this class is stateful and tracks the position, we rewind and store the state, // prepend the length, then reset it back to the end of the string. position = oldPosition; int length = newPosition - oldPosition - minLengthVarIntSize; writeUInt32NoTag(length); position = newPosition; } else { int length = Utf8.encodedLength(value); writeUInt32NoTag(length); position = Utf8.encode(value, buffer, position, spaceLeft()); } } catch (UnpairedSurrogateException e) { // Roll back the change - we fall back to inefficient path. position = oldPosition; // TODO(nathanmittler): We should throw an IOException here instead. inefficientWriteStringNoTag(value, e); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } } @Override public void flush() { // Do nothing. } @Override public final int spaceLeft() { return limit - position; } @Override public final int getTotalBytesWritten() { return position - offset; } }
A CodedOutputStream that writes directly to a heap ByteBuffer. Writes are done directly to the underlying array. The buffer position is only updated after a flush.
/** * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are done * directly to the underlying array. The buffer position is only updated after a flush. */
private static final class HeapNioEncoder extends ArrayEncoder { private final ByteBuffer byteBuffer; private int initialPosition; HeapNioEncoder(ByteBuffer byteBuffer) { super( byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining()); this.byteBuffer = byteBuffer; this.initialPosition = byteBuffer.position(); } @Override public void flush() { // Update the position on the buffer. byteBuffer.position(initialPosition + getTotalBytesWritten()); } }
A CodedOutputStream that writes directly to a direct ByteBuffer, using only safe operations..
/** * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer}, using only * safe operations.. */
private static final class SafeDirectNioEncoder extends CodedOutputStream { private final ByteBuffer originalBuffer; private final ByteBuffer buffer; private final int initialPosition; SafeDirectNioEncoder(ByteBuffer buffer) { this.originalBuffer = buffer; this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); initialPosition = buffer.position(); } @Override public void writeTag(final int fieldNumber, final int wireType) throws IOException { writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); } @Override public void writeInt32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeInt32NoTag(value); } @Override public void writeUInt32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt32NoTag(value); } @Override public void writeFixed32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeFixed32NoTag(value); } @Override public void writeUInt64(final int fieldNumber, final long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt64NoTag(value); } @Override public void writeFixed64(final int fieldNumber, final long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeFixed64NoTag(value); } @Override public void writeBool(final int fieldNumber, final boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); write((byte) (value ? 1 : 0)); } @Override public void writeString(final int fieldNumber, final String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } @Override public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } @Override public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { writeByteArray(fieldNumber, value, 0, value.length); } @Override public void writeByteArray( final int fieldNumber, final byte[] value, final int offset, final int length) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @Override public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(value.capacity()); writeRawBytes(value); } @Override public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value); } @Override void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value, schema); } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeMessageNoTag(final MessageLite value) throws IOException { writeUInt32NoTag(value.getSerializedSize()); value.writeTo(this); } @Override void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public void write(byte value) throws IOException { try { buffer.put(value); } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeBytesNoTag(final ByteString value) throws IOException { writeUInt32NoTag(value.size()); value.writeTo(this); } @Override public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { writeUInt32NoTag(length); write(value, offset, length); } @Override public void writeRawBytes(final ByteBuffer value) throws IOException { if (value.hasArray()) { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); duplicated.clear(); write(duplicated); } } @Override public void writeInt32NoTag(int value) throws IOException { if (value >= 0) { writeUInt32NoTag(value); } else { // Must sign-extend. writeUInt64NoTag(value); } } @Override public void writeUInt32NoTag(int value) throws IOException { try { while (true) { if ((value & ~0x7F) == 0) { buffer.put((byte) value); return; } else { buffer.put((byte) ((value & 0x7F) | 0x80)); value >>>= 7; } } } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeFixed32NoTag(int value) throws IOException { try { buffer.putInt(value); } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeUInt64NoTag(long value) throws IOException { try { while (true) { if ((value & ~0x7FL) == 0) { buffer.put((byte) value); return; } else { buffer.put((byte) (((int) value & 0x7F) | 0x80)); value >>>= 7; } } } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeFixed64NoTag(long value) throws IOException { try { buffer.putLong(value); } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void write(byte[] value, int offset, int length) throws IOException { try { buffer.put(value, offset, length); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeLazy(byte[] value, int offset, int length) throws IOException { write(value, offset, length); } @Override public void write(ByteBuffer value) throws IOException { try { buffer.put(value); } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeLazy(ByteBuffer value) throws IOException { write(value); } @Override public void writeStringNoTag(String value) throws IOException { final int startPos = buffer.position(); try { // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), // and at most 3 times of it. We take advantage of this in both branches below. final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR; final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize); final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); if (minLengthVarIntSize == maxLengthVarIntSize) { // Save the current position and increment past the length field. We'll come back // and write the length field after the encoding is complete. final int startOfBytes = buffer.position() + minLengthVarIntSize; buffer.position(startOfBytes); // Encode the string. encode(value); // Now go back to the beginning and write the length. int endOfBytes = buffer.position(); buffer.position(startPos); writeUInt32NoTag(endOfBytes - startOfBytes); // Reposition the buffer past the written data. buffer.position(endOfBytes); } else { final int length = Utf8.encodedLength(value); writeUInt32NoTag(length); encode(value); } } catch (UnpairedSurrogateException e) { // Roll back the change and convert to an IOException. buffer.position(startPos); // TODO(nathanmittler): We should throw an IOException here instead. inefficientWriteStringNoTag(value, e); } catch (IllegalArgumentException e) { // Thrown by buffer.position() if out of range. throw new OutOfSpaceException(e); } } @Override public void flush() { // Update the position of the original buffer. originalBuffer.position(buffer.position()); } @Override public int spaceLeft() { return buffer.remaining(); } @Override public int getTotalBytesWritten() { return buffer.position() - initialPosition; } private void encode(String value) throws IOException { try { Utf8.encodeUtf8(value, buffer); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } } }
A CodedOutputStream that writes directly to a direct ByteBuffer using sun.misc.Unsafe.
/** * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer} using {@code * sun.misc.Unsafe}. */
private static final class UnsafeDirectNioEncoder extends CodedOutputStream { private final ByteBuffer originalBuffer; private final ByteBuffer buffer; private final long address; private final long initialPosition; private final long limit; private final long oneVarintLimit; private long position; UnsafeDirectNioEncoder(ByteBuffer buffer) { this.originalBuffer = buffer; this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); address = UnsafeUtil.addressOffset(buffer); initialPosition = address + buffer.position(); limit = address + buffer.limit(); oneVarintLimit = limit - MAX_VARINT_SIZE; position = initialPosition; } static boolean isSupported() { return UnsafeUtil.hasUnsafeByteBufferOperations(); } @Override public void writeTag(int fieldNumber, int wireType) throws IOException { writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); } @Override public void writeInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeInt32NoTag(value); } @Override public void writeUInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt32NoTag(value); } @Override public void writeFixed32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeFixed32NoTag(value); } @Override public void writeUInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeUInt64NoTag(value); } @Override public void writeFixed64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); writeFixed64NoTag(value); } @Override public void writeBool(int fieldNumber, boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); write((byte) (value ? 1 : 0)); } @Override public void writeString(int fieldNumber, String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } @Override public void writeBytes(int fieldNumber, ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } @Override public void writeByteArray(int fieldNumber, byte[] value) throws IOException { writeByteArray(fieldNumber, value, 0, value.length); } @Override public void writeByteArray(int fieldNumber, byte[] value, int offset, int length) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @Override public void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(value.capacity()); writeRawBytes(value); } @Override public void writeMessage(int fieldNumber, MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value); } @Override void writeMessage(int fieldNumber, MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value, schema); } @Override public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeRawMessageSetExtension(int fieldNumber, ByteString value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeMessageNoTag(MessageLite value) throws IOException { writeUInt32NoTag(value.getSerializedSize()); value.writeTo(this); } @Override void writeMessageNoTag(MessageLite value, Schema schema) throws IOException { writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public void write(byte value) throws IOException { if (position >= limit) { throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); } UnsafeUtil.putByte(position++, value); } @Override public void writeBytesNoTag(ByteString value) throws IOException { writeUInt32NoTag(value.size()); value.writeTo(this); } @Override public void writeByteArrayNoTag(byte[] value, int offset, int length) throws IOException { writeUInt32NoTag(length); write(value, offset, length); } @Override public void writeRawBytes(ByteBuffer value) throws IOException { if (value.hasArray()) { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); duplicated.clear(); write(duplicated); } } @Override public void writeInt32NoTag(int value) throws IOException { if (value >= 0) { writeUInt32NoTag(value); } else { // Must sign-extend. writeUInt64NoTag(value); } } @Override public void writeUInt32NoTag(int value) throws IOException { if (position <= oneVarintLimit) { // Optimization to avoid bounds checks on each iteration. while (true) { if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(position++, (byte) value); return; } else { UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80)); value >>>= 7; } } } else { while (position < limit) { if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(position++, (byte) value); return; } else { UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80)); value >>>= 7; } } throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); } } @Override public void writeFixed32NoTag(int value) throws IOException { buffer.putInt(bufferPos(position), value); position += FIXED32_SIZE; } @Override public void writeUInt64NoTag(long value) throws IOException { if (position <= oneVarintLimit) { // Optimization to avoid bounds checks on each iteration. while (true) { if ((value & ~0x7FL) == 0) { UnsafeUtil.putByte(position++, (byte) value); return; } else { UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80)); value >>>= 7; } } } else { while (position < limit) { if ((value & ~0x7FL) == 0) { UnsafeUtil.putByte(position++, (byte) value); return; } else { UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80)); value >>>= 7; } } throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); } } @Override public void writeFixed64NoTag(long value) throws IOException { buffer.putLong(bufferPos(position), value); position += FIXED64_SIZE; } @Override public void write(byte[] value, int offset, int length) throws IOException { if (value == null || offset < 0 || length < 0 || (value.length - length) < offset || (limit - length) < position) { if (value == null) { throw new NullPointerException("value"); } throw new OutOfSpaceException( String.format("Pos: %d, limit: %d, len: %d", position, limit, length)); } UnsafeUtil.copyMemory(value, offset, position, length); position += length; } @Override public void writeLazy(byte[] value, int offset, int length) throws IOException { write(value, offset, length); } @Override public void write(ByteBuffer value) throws IOException { try { int length = value.remaining(); repositionBuffer(position); buffer.put(value); position += length; } catch (BufferOverflowException e) { throw new OutOfSpaceException(e); } } @Override public void writeLazy(ByteBuffer value) throws IOException { write(value); } @Override public void writeStringNoTag(String value) throws IOException { long prevPos = position; try { // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), // and at most 3 times of it. We take advantage of this in both branches below. int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR; int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize); int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); if (minLengthVarIntSize == maxLengthVarIntSize) { // Save the current position and increment past the length field. We'll come back // and write the length field after the encoding is complete. int stringStart = bufferPos(position) + minLengthVarIntSize; buffer.position(stringStart); // Encode the string. Utf8.encodeUtf8(value, buffer); // Write the length and advance the position. int length = buffer.position() - stringStart; writeUInt32NoTag(length); position += length; } else { // Calculate and write the encoded length. int length = Utf8.encodedLength(value); writeUInt32NoTag(length); // Write the string and advance the position. repositionBuffer(position); Utf8.encodeUtf8(value, buffer); position += length; } } catch (UnpairedSurrogateException e) { // Roll back the change and convert to an IOException. position = prevPos; repositionBuffer(position); // TODO(nathanmittler): We should throw an IOException here instead. inefficientWriteStringNoTag(value, e); } catch (IllegalArgumentException e) { // Thrown by buffer.position() if out of range. throw new OutOfSpaceException(e); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } } @Override public void flush() { // Update the position of the original buffer. originalBuffer.position(bufferPos(position)); } @Override public int spaceLeft() { return (int) (limit - position); } @Override public int getTotalBytesWritten() { return (int) (position - initialPosition); } private void repositionBuffer(long pos) { buffer.position(bufferPos(pos)); } private int bufferPos(long pos) { return (int) (pos - address); } }
Abstract base class for buffered encoders.
/** Abstract base class for buffered encoders. */
private abstract static class AbstractBufferedEncoder extends CodedOutputStream { final byte[] buffer; final int limit; int position; int totalBytesWritten; AbstractBufferedEncoder(int bufferSize) { if (bufferSize < 0) { throw new IllegalArgumentException("bufferSize must be >= 0"); } // As an optimization, we require that the buffer be able to store at least 2 // varints so that we can buffer any integer write (tag + value). This reduces the // number of range checks for a single write to 1 (i.e. if there is not enough space // to buffer the tag+value, flush and then buffer it). this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)]; this.limit = buffer.length; } @Override public final int spaceLeft() { throw new UnsupportedOperationException( "spaceLeft() can only be called on CodedOutputStreams that are " + "writing to a flat array or ByteBuffer."); } @Override public final int getTotalBytesWritten() { return totalBytesWritten; }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void buffer(byte value) { buffer[position++] = value; totalBytesWritten++; }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferTag(final int fieldNumber, final int wireType) { bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferInt32NoTag(final int value) { if (value >= 0) { bufferUInt32NoTag(value); } else { // Must sign-extend. bufferUInt64NoTag(value); } }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferUInt32NoTag(int value) { if (HAS_UNSAFE_ARRAY_OPERATIONS) { final long originalPos = position; while (true) { if ((value & ~0x7F) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); break; } else { UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80)); value >>>= 7; } } int delta = (int) (position - originalPos); totalBytesWritten += delta; } else { while (true) { if ((value & ~0x7F) == 0) { buffer[position++] = (byte) value; totalBytesWritten++; return; } else { buffer[position++] = (byte) ((value & 0x7F) | 0x80); totalBytesWritten++; value >>>= 7; } } } }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferUInt64NoTag(long value) { if (HAS_UNSAFE_ARRAY_OPERATIONS) { final long originalPos = position; while (true) { if ((value & ~0x7FL) == 0) { UnsafeUtil.putByte(buffer, position++, (byte) value); break; } else { UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80)); value >>>= 7; } } int delta = (int) (position - originalPos); totalBytesWritten += delta; } else { while (true) { if ((value & ~0x7FL) == 0) { buffer[position++] = (byte) value; totalBytesWritten++; return; } else { buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); totalBytesWritten++; value >>>= 7; } } } }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferFixed32NoTag(int value) { buffer[position++] = (byte) (value & 0xFF); buffer[position++] = (byte) ((value >> 8) & 0xFF); buffer[position++] = (byte) ((value >> 16) & 0xFF); buffer[position++] = (byte) ((value >> 24) & 0xFF); totalBytesWritten += FIXED32_SIZE; }
This method does not perform bounds checking on the array. Checking array bounds is the responsibility of the caller.
/** * This method does not perform bounds checking on the array. Checking array bounds is the * responsibility of the caller. */
final void bufferFixed64NoTag(long value) { buffer[position++] = (byte) (value & 0xFF); buffer[position++] = (byte) ((value >> 8) & 0xFF); buffer[position++] = (byte) ((value >> 16) & 0xFF); buffer[position++] = (byte) ((value >> 24) & 0xFF); buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); totalBytesWritten += FIXED64_SIZE; } }
A CodedOutputStream that decorates a ByteOutput. It internal buffer only to support string encoding operations. All other writes are just passed through to the ByteOutput.
/** * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to * support string encoding operations. All other writes are just passed through to the {@link * ByteOutput}. */
private static final class ByteOutputEncoder extends AbstractBufferedEncoder { private final ByteOutput out; ByteOutputEncoder(ByteOutput out, int bufferSize) { super(bufferSize); if (out == null) { throw new NullPointerException("out"); } this.out = out; } @Override public void writeTag(final int fieldNumber, final int wireType) throws IOException { writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); } @Override public void writeInt32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferInt32NoTag(value); } @Override public void writeUInt32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferUInt32NoTag(value); } @Override public void writeFixed32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); bufferFixed32NoTag(value); } @Override public void writeUInt64(final int fieldNumber, final long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferUInt64NoTag(value); } @Override public void writeFixed64(final int fieldNumber, final long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); bufferFixed64NoTag(value); } @Override public void writeBool(final int fieldNumber, final boolean value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + 1); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); buffer((byte) (value ? 1 : 0)); } @Override public void writeString(final int fieldNumber, final String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } @Override public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } @Override public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { writeByteArray(fieldNumber, value, 0, value.length); } @Override public void writeByteArray( final int fieldNumber, final byte[] value, final int offset, final int length) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @Override public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(value.capacity()); writeRawBytes(value); } @Override public void writeBytesNoTag(final ByteString value) throws IOException { writeUInt32NoTag(value.size()); value.writeTo(this); } @Override public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { writeUInt32NoTag(length); write(value, offset, length); } @Override public void writeRawBytes(final ByteBuffer value) throws IOException { if (value.hasArray()) { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); duplicated.clear(); write(duplicated); } } @Override public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value); } @Override void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value, schema); } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeMessageNoTag(final MessageLite value) throws IOException { writeUInt32NoTag(value.getSerializedSize()); value.writeTo(this); } @Override void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public void write(byte value) throws IOException { if (position == limit) { doFlush(); } buffer(value); } @Override public void writeInt32NoTag(int value) throws IOException { if (value >= 0) { writeUInt32NoTag(value); } else { // Must sign-extend. writeUInt64NoTag(value); } } @Override public void writeUInt32NoTag(int value) throws IOException { flushIfNotAvailable(MAX_VARINT32_SIZE); bufferUInt32NoTag(value); } @Override public void writeFixed32NoTag(final int value) throws IOException { flushIfNotAvailable(FIXED32_SIZE); bufferFixed32NoTag(value); } @Override public void writeUInt64NoTag(long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE); bufferUInt64NoTag(value); } @Override public void writeFixed64NoTag(final long value) throws IOException { flushIfNotAvailable(FIXED64_SIZE); bufferFixed64NoTag(value); } @Override public void writeStringNoTag(String value) throws IOException { // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), // and at most 3 times of it. We take advantage of this in both branches below. final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); // If we are streaming and the potential length is too big to fit in our buffer, we take the // slower path. if (maxLengthVarIntSize + maxLength > limit) { // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() // does the same internally and then does *another copy* to return a byte[] of exactly the // right size. We can skip that copy and just writeRawBytes up to the actualLength of the // UTF-8 encoded bytes. final byte[] encodedBytes = new byte[maxLength]; int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); writeUInt32NoTag(actualLength); writeLazy(encodedBytes, 0, actualLength); return; } // Fast path: we have enough space available in our buffer for the string... if (maxLengthVarIntSize + maxLength > limit - position) { // Flush to free up space. doFlush(); } final int oldPosition = position; try { // Optimize for the case where we know this length results in a constant varint length as // this saves a pass for measuring the length of the string. final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); if (minLengthVarIntSize == maxLengthVarIntSize) { position = oldPosition + minLengthVarIntSize; int newPosition = Utf8.encode(value, buffer, position, limit - position); // Since this class is stateful and tracks the position, we rewind and store the state, // prepend the length, then reset it back to the end of the string. position = oldPosition; int length = newPosition - oldPosition - minLengthVarIntSize; bufferUInt32NoTag(length); position = newPosition; totalBytesWritten += length; } else { int length = Utf8.encodedLength(value); bufferUInt32NoTag(length); position = Utf8.encode(value, buffer, position, length); totalBytesWritten += length; } } catch (UnpairedSurrogateException e) { // Roll back the change and convert to an IOException. totalBytesWritten -= position - oldPosition; position = oldPosition; // TODO(nathanmittler): We should throw an IOException here instead. inefficientWriteStringNoTag(value, e); } catch (IndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } } @Override public void flush() throws IOException { if (position > 0) { // Flush the buffer. doFlush(); } } @Override public void write(byte[] value, int offset, int length) throws IOException { flush(); out.write(value, offset, length); totalBytesWritten += length; } @Override public void writeLazy(byte[] value, int offset, int length) throws IOException { flush(); out.writeLazy(value, offset, length); totalBytesWritten += length; } @Override public void write(ByteBuffer value) throws IOException { flush(); int length = value.remaining(); out.write(value); totalBytesWritten += length; } @Override public void writeLazy(ByteBuffer value) throws IOException { flush(); int length = value.remaining(); out.writeLazy(value); totalBytesWritten += length; } private void flushIfNotAvailable(int requiredSize) throws IOException { if (limit - position < requiredSize) { doFlush(); } } private void doFlush() throws IOException { out.write(buffer, 0, position); position = 0; } }
An CodedOutputStream that decorates an OutputStream. It performs internal buffering to optimize writes to the OutputStream.
/** * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal * buffering to optimize writes to the {@link OutputStream}. */
private static final class OutputStreamEncoder extends AbstractBufferedEncoder { private final OutputStream out; OutputStreamEncoder(OutputStream out, int bufferSize) { super(bufferSize); if (out == null) { throw new NullPointerException("out"); } this.out = out; } @Override public void writeTag(final int fieldNumber, final int wireType) throws IOException { writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); } @Override public void writeInt32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferInt32NoTag(value); } @Override public void writeUInt32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferUInt32NoTag(value); } @Override public void writeFixed32(final int fieldNumber, final int value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); bufferFixed32NoTag(value); } @Override public void writeUInt64(final int fieldNumber, final long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE * 2); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); bufferUInt64NoTag(value); } @Override public void writeFixed64(final int fieldNumber, final long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); bufferFixed64NoTag(value); } @Override public void writeBool(final int fieldNumber, final boolean value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE + 1); bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); buffer((byte) (value ? 1 : 0)); } @Override public void writeString(final int fieldNumber, final String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } @Override public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } @Override public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { writeByteArray(fieldNumber, value, 0, value.length); } @Override public void writeByteArray( final int fieldNumber, final byte[] value, final int offset, final int length) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @Override public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeUInt32NoTag(value.capacity()); writeRawBytes(value); } @Override public void writeBytesNoTag(final ByteString value) throws IOException { writeUInt32NoTag(value.size()); value.writeTo(this); } @Override public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { writeUInt32NoTag(length); write(value, offset, length); } @Override public void writeRawBytes(final ByteBuffer value) throws IOException { if (value.hasArray()) { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); duplicated.clear(); write(duplicated); } } @Override public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value); } @Override void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeMessageNoTag(value, schema); } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); } @Override public void writeMessageNoTag(final MessageLite value) throws IOException { writeUInt32NoTag(value.getSerializedSize()); value.writeTo(this); } @Override void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); schema.writeTo(value, wrapper); } @Override public void write(byte value) throws IOException { if (position == limit) { doFlush(); } buffer(value); } @Override public void writeInt32NoTag(int value) throws IOException { if (value >= 0) { writeUInt32NoTag(value); } else { // Must sign-extend. writeUInt64NoTag(value); } } @Override public void writeUInt32NoTag(int value) throws IOException { flushIfNotAvailable(MAX_VARINT32_SIZE); bufferUInt32NoTag(value); } @Override public void writeFixed32NoTag(final int value) throws IOException { flushIfNotAvailable(FIXED32_SIZE); bufferFixed32NoTag(value); } @Override public void writeUInt64NoTag(long value) throws IOException { flushIfNotAvailable(MAX_VARINT_SIZE); bufferUInt64NoTag(value); } @Override public void writeFixed64NoTag(final long value) throws IOException { flushIfNotAvailable(FIXED64_SIZE); bufferFixed64NoTag(value); } @Override public void writeStringNoTag(String value) throws IOException { try { // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), // and at most 3 times of it. We take advantage of this in both branches below. final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); // If we are streaming and the potential length is too big to fit in our buffer, we take the // slower path. if (maxLengthVarIntSize + maxLength > limit) { // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() // does the same internally and then does *another copy* to return a byte[] of exactly the // right size. We can skip that copy and just writeRawBytes up to the actualLength of the // UTF-8 encoded bytes. final byte[] encodedBytes = new byte[maxLength]; int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); writeUInt32NoTag(actualLength); writeLazy(encodedBytes, 0, actualLength); return; } // Fast path: we have enough space available in our buffer for the string... if (maxLengthVarIntSize + maxLength > limit - position) { // Flush to free up space. doFlush(); } // Optimize for the case where we know this length results in a constant varint length as // this saves a pass for measuring the length of the string. final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); int oldPosition = position; final int length; try { if (minLengthVarIntSize == maxLengthVarIntSize) { position = oldPosition + minLengthVarIntSize; int newPosition = Utf8.encode(value, buffer, position, limit - position); // Since this class is stateful and tracks the position, we rewind and store the // state, prepend the length, then reset it back to the end of the string. position = oldPosition; length = newPosition - oldPosition - minLengthVarIntSize; bufferUInt32NoTag(length); position = newPosition; } else { length = Utf8.encodedLength(value); bufferUInt32NoTag(length); position = Utf8.encode(value, buffer, position, length); } totalBytesWritten += length; } catch (UnpairedSurrogateException e) { // Be extra careful and restore the original position for retrying the write with the // less efficient path. totalBytesWritten -= position - oldPosition; position = oldPosition; throw e; } catch (ArrayIndexOutOfBoundsException e) { throw new OutOfSpaceException(e); } } catch (UnpairedSurrogateException e) { inefficientWriteStringNoTag(value, e); } } @Override public void flush() throws IOException { if (position > 0) { // Flush the buffer. doFlush(); } } @Override public void write(byte[] value, int offset, int length) throws IOException { if (limit - position >= length) { // We have room in the current buffer. System.arraycopy(value, offset, buffer, position, length); position += length; totalBytesWritten += length; } else { // Write extends past current buffer. Fill the rest of this buffer and // flush. final int bytesWritten = limit - position; System.arraycopy(value, offset, buffer, position, bytesWritten); offset += bytesWritten; length -= bytesWritten; position = limit; totalBytesWritten += bytesWritten; doFlush(); // Now deal with the rest. // Since we have an output stream, this is our buffer // and buffer offset == 0 if (length <= limit) { // Fits in new buffer. System.arraycopy(value, offset, buffer, 0, length); position = length; } else { // Write is very big. Let's do it all at once. out.write(value, offset, length); } totalBytesWritten += length; } } @Override public void writeLazy(byte[] value, int offset, int length) throws IOException { write(value, offset, length); } @Override public void write(ByteBuffer value) throws IOException { int length = value.remaining(); if (limit - position >= length) { // We have room in the current buffer. value.get(buffer, position, length); position += length; totalBytesWritten += length; } else { // Write extends past current buffer. Fill the rest of this buffer and // flush. final int bytesWritten = limit - position; value.get(buffer, position, bytesWritten); length -= bytesWritten; position = limit; totalBytesWritten += bytesWritten; doFlush(); // Now deal with the rest. // Since we have an output stream, this is our buffer // and buffer offset == 0 while (length > limit) { // Copy data into the buffer before writing it to OutputStream. value.get(buffer, 0, limit); out.write(buffer, 0, limit); length -= limit; totalBytesWritten += limit; } value.get(buffer, 0, length); position = length; totalBytesWritten += length; } } @Override public void writeLazy(ByteBuffer value) throws IOException { write(value); } private void flushIfNotAvailable(int requiredSize) throws IOException { if (limit - position < requiredSize) { doFlush(); } } private void doFlush() throws IOException { out.write(buffer, 0, position); position = 0; } } }