1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpackage com.google.protobuf;
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport static java.lang.Math.max;
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport com.google.protobuf.Utf8.UnpairedSurrogateException;
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.IOException;
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.OutputStream;
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.lang.reflect.Field;
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.BufferOverflowException;
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.ByteBuffer;
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.ByteOrder;
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.security.AccessController;
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.security.PrivilegedExceptionAction;
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.logging.Level;
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.logging.Logger;
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Encodes and writes protocol message fields.
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>This class contains two kinds of methods:  methods that write specific
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * protocol message constructs and field types (e.g. {@link #writeTag} and
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link #writeInt32}) and methods that write low-level values (e.g.
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * writing encoded protocol messages, you should use the former methods, but if
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * you are writing some other format of your own design, use the latter.
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>This class is totally unsynchronized.
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpublic abstract class CodedOutputStream extends ByteOutput {
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final sun.misc.Unsafe UNSAFE = getUnsafe();
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final int FIXED_32_SIZE = 4;
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final int FIXED_64_SIZE = 8;
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final int MAX_VARINT_SIZE = 10;
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE;
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The buffer size used in {@link #newInstance(OutputStream)}.
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int DEFAULT_BUFFER_SIZE = 4096;
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Returns the buffer size to efficiently write dataLength bytes to this
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * CodedOutputStream. Used by AbstractMessageLite.
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @return the buffer size to efficiently write dataLength bytes to this
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *         CodedOutputStream.
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  static int computePreferredBufferSize(int dataLength) {
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (dataLength > DEFAULT_BUFFER_SIZE) {
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return DEFAULT_BUFFER_SIZE;
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return dataLength;
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}.
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * difficult to debug.
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(final OutputStream output) {
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return newInstance(output, DEFAULT_BUFFER_SIZE);
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * buffer size.
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * difficult to debug.
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) {
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return new OutputStreamEncoder(output, bufferSize);
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} that writes directly to the given
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * byte array.  If more bytes are written than fit in the array,
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * array is faster than writing to an {@code OutputStream}.  See also
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@link ByteString#newCodedBuilder}.
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(final byte[] flatArray) {
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return newInstance(flatArray, 0, flatArray.length);
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} that writes directly to the given
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * byte array slice.  If more bytes are written than fit in the slice,
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * array is faster than writing to an {@code OutputStream}.  See also
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@link ByteString#newCodedBuilder}.
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final byte[] flatArray, final int offset, final int length) {
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return new ArrayEncoder(flatArray, offset, length);
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (byteBuffer.hasArray()) {
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return new NioHeapEncoder(byteBuffer);
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return new NioEncoder(byteBuffer);
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated the size parameter is no longer used since use of an internal buffer is useless
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * instead.
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      @SuppressWarnings("unused") int unused) {
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return newInstance(byteBuffer);
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}.
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * so may result in corrupted data, which would be difficult to debug.
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param byteOutput the output target for encoded bytes.
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param bufferSize the size of the internal scratch buffer to be used for string encoding.
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * string.
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) {
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (bufferSize < 0) {
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw new IllegalArgumentException("bufferSize must be positive");
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return new ByteOutputEncoder(byteOutput, bufferSize);
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Disallow construction outside of this class.
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private CodedOutputStream() {
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // -----------------------------------------------------------------
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Encode and write a tag. */
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeTag(int fieldNumber, int wireType) throws IOException;
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code int32} field, including tag, to the stream. */
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeInt32(int fieldNumber, int value) throws IOException;
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code uint32} field, including tag, to the stream. */
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeUInt32(int fieldNumber, int value) throws IOException;
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code sint32} field, including tag, to the stream. */
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSInt32(final int fieldNumber, final int value) throws IOException {
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt32(fieldNumber, encodeZigZag32(value));
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code fixed32} field, including tag, to the stream. */
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeFixed32(int fieldNumber, int value) throws IOException;
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code sfixed32} field, including tag, to the stream. */
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSFixed32(final int fieldNumber, final int value) throws IOException {
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed32(fieldNumber, value);
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code int64} field, including tag, to the stream. */
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeInt64(final int fieldNumber, final long value) throws IOException {
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt64(fieldNumber, value);
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code uint64} field, including tag, to the stream. */
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeUInt64(int fieldNumber, long value) throws IOException;
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code sint64} field, including tag, to the stream. */
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSInt64(final int fieldNumber, final long value) throws IOException {
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt64(fieldNumber, encodeZigZag64(value));
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code fixed64} field, including tag, to the stream. */
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeFixed64(int fieldNumber, long value) throws IOException;
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code sfixed64} field, including tag, to the stream. */
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSFixed64(final int fieldNumber, final long value) throws IOException {
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed64(fieldNumber, value);
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code float} field, including tag, to the stream. */
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeFloat(final int fieldNumber, final float value) throws IOException {
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code double} field, including tag, to the stream. */
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeDouble(final int fieldNumber, final double value) throws IOException {
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bool} field, including tag, to the stream. */
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write an enum field, including tag, to the stream. The provided value is the numeric
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * value used to represent the enum value on the wire (not the enum ordinal value).
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeEnum(final int fieldNumber, final int value) throws IOException {
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeInt32(fieldNumber, value);
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code string} field, including tag, to the stream. */
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeString(int fieldNumber, String value) throws IOException;
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field, including tag, to the stream. */
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException;
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field, including tag, to the stream. */
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException;
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field, including tag, to the stream. */
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException;
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a {@code bytes} field, including tag, to the stream.
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * This method will write all content of the ByteBuffer regardless of the
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * current position and limit (i.e., the number of bytes to be written is
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * value.capacity(), not value.remaining()). Furthermore, this method doesn't
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * alter the state of the passed-in ByteBuffer. Its position, limit, mark,
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * etc. will remain unchanged. If you only want to write the remaining bytes
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * of a ByteBuffer, you can call
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a single byte.
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawByte(final byte value) throws IOException {
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    write(value);
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a single byte, represented by an integer value. */
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawByte(final int value) throws IOException {
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    write((byte) value);
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an array of bytes. */
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawBytes(final byte[] value) throws IOException {
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    write(value, 0, value.length);
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write part of an array of bytes.
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException {
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    write(value, offset, length);
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a byte string. */
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawBytes(final ByteString value) throws IOException {
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    value.writeTo(this);
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a ByteBuffer. This method will write all content of the ByteBuffer
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * regardless of the current position and limit (i.e., the number of bytes
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * to be written is value.capacity(), not value.remaining()). Furthermore,
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * this method doesn't alter the state of the passed-in ByteBuffer. Its
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * position, limit, mark, etc. will remain unchanged. If you only want to
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * write the remaining bytes of a ByteBuffer, you can call
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code writeRawBytes(byteBuffer.slice())}.
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an embedded message field, including tag, to the stream. */
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeMessage(final int fieldNumber, final MessageLite value)
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException;
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a MessageSet extension field to the stream.  For historical reasons,
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * the wire format differs from normal fields.
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException;
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write an unparsed MessageSet extension field to the stream.  For
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * historical reasons, the wire format differs from normal fields.
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException;
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // -----------------------------------------------------------------
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code int32} field to the stream. */
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeInt32NoTag(final int value) throws IOException;
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code uint32} field to the stream. */
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeUInt32NoTag(int value) throws IOException;
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code sint32} field to the stream. */
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSInt32NoTag(final int value) throws IOException {
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt32NoTag(encodeZigZag32(value));
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code fixed32} field to the stream. */
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeFixed32NoTag(int value) throws IOException;
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code sfixed32} field to the stream. */
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSFixed32NoTag(final int value) throws IOException {
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed32NoTag(value);
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an {@code int64} field to the stream. */
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeInt64NoTag(final long value) throws IOException {
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt64NoTag(value);
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code uint64} field to the stream. */
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeUInt64NoTag(long value) throws IOException;
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code sint64} field to the stream. */
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSInt64NoTag(final long value) throws IOException {
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt64NoTag(encodeZigZag64(value));
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code fixed64} field to the stream. */
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeFixed64NoTag(long value) throws IOException;
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code sfixed64} field to the stream. */
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeSFixed64NoTag(final long value) throws IOException {
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed64NoTag(value);
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code float} field to the stream. */
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeFloatNoTag(final float value) throws IOException {
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed32NoTag(Float.floatToRawIntBits(value));
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code double} field to the stream. */
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeDoubleNoTag(final double value) throws IOException {
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed64NoTag(Double.doubleToRawLongBits(value));
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bool} field to the stream. */
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeBoolNoTag(final boolean value) throws IOException {
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    write((byte) (value ? 1 : 0));
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write an enum field to the stream. The provided value is the numeric
416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * value used to represent the enum value on the wire (not the enum ordinal value).
417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeEnumNoTag(final int value) throws IOException {
419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeInt32NoTag(value);
420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code string} field to the stream. */
423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(dweis): Document behavior on ill-formed UTF-16 input.
424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeStringNoTag(String value) throws IOException;
426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field to the stream. */
428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeBytesNoTag(final ByteString value) throws IOException;
430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field to the stream. */
432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeByteArrayNoTag(final byte[] value) throws IOException {
433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeByteArrayNoTag(value, 0, value.length);
434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write an embedded message field to the stream. */
437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Abstract to avoid overhead of additional virtual method calls.
438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  //=================================================================
441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @ExperimentalApi
443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Override
444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void write(byte value) throws IOException;
445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @ExperimentalApi
447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Override
448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void write(byte[] value, int offset, int length) throws IOException;
449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @ExperimentalApi
451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Override
452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Override
455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void write(ByteBuffer value) throws IOException;
456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @ExperimentalApi
458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Override
459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void writeLazy(ByteBuffer value) throws IOException;
460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code int32} field, including tag.
467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeInt32Size(final int fieldNumber, final int value) {
469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code uint32} field, including tag.
475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeUInt32Size(final int fieldNumber, final int value) {
477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sint32} field, including tag.
483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSInt32Size(final int fieldNumber, final int value) {
485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code fixed32} field, including tag.
491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFixed32Size(final int fieldNumber, final int value) {
493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sfixed32} field, including tag.
499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSFixed32Size(final int fieldNumber, final int value) {
501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code int64} field, including tag.
507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeInt64Size(final int fieldNumber, final long value) {
509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code uint64} field, including tag.
515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeUInt64Size(final int fieldNumber, final long value) {
517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sint64} field, including tag.
523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSInt64Size(final int fieldNumber, final long value) {
525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code fixed64} field, including tag.
531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFixed64Size(final int fieldNumber, final long value) {
533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sfixed64} field, including tag.
539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSFixed64Size(final int fieldNumber, final long value) {
541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code float} field, including tag.
547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFloatSize(final int fieldNumber, final float value) {
549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code double} field, including tag.
555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeDoubleSize(final int fieldNumber, final double value) {
557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bool} field, including tag.
563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeBoolSize(final int fieldNumber, final boolean value) {
565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * enum field, including tag. The provided value is the numeric
571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * value used to represent the enum value on the wire (not the enum ordinal value).
572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeEnumSize(final int fieldNumber, final int value) {
574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code string} field, including tag.
580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeStringSize(final int fieldNumber, final String value) {
582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field, including tag.
588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeBytesSize(final int fieldNumber, final ByteString value) {
590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field, including tag.
596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeByteArraySize(final int fieldNumber, final byte[] value) {
598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field, including tag.
604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) {
606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * embedded message in lazy field, including tag.
612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) {
614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * embedded message field, including tag.
620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeMessageSize(final int fieldNumber, final MessageLite value) {
622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * MessageSet extension to the stream.  For historical reasons,
628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * the wire format differs from normal fields.
629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) {
631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * unparsed MessageSet extension field to the stream.  For
639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * historical reasons, the wire format differs from normal fields.
640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeRawMessageSetExtensionSize(
642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int fieldNumber, final ByteString value) {
643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * lazily parsed MessageSet extension field to the stream.  For
651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * historical reasons, the wire format differs from normal fields.
652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeLazyFieldMessageSetExtensionSize(
654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int fieldNumber, final LazyFieldLite value) {
655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // -----------------------------------------------------------------
661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Compute the number of bytes that would be needed to encode a tag. */
663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeTagSize(final int fieldNumber) {
664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0));
665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code int32} field, including tag.
670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeInt32SizeNoTag(final int value) {
672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (value >= 0) {
673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return computeUInt32SizeNoTag(value);
674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Must sign-extend.
676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return MAX_VARINT_SIZE;
677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
681b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
682b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code uint32} field.
683b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
684b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeUInt32SizeNoTag(final int value) {
685b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0 <<  7)) == 0) {
686b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 1;
687b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
688b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0 << 14)) == 0) {
689b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 2;
690b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
691b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0 << 21)) == 0) {
692b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 3;
693b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
694b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0 << 28)) == 0) {
695b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 4;
696b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
697b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return 5;
698b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
700b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
701b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
702b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sint32} field.
703b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
704b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSInt32SizeNoTag(final int value) {
705b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt32SizeNoTag(encodeZigZag32(value));
706b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
707b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
708b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
709b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
710b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code fixed32} field.
711b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_32_SIZE;
714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sfixed32} field.
719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_32_SIZE;
722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code int64} field, including tag.
727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeInt64SizeNoTag(final long value) {
729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt64SizeNoTag(value);
730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code uint64} field, including tag.
735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeUInt64SizeNoTag(long value) {
737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // handle two popular special cases up front ...
738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0L << 7)) == 0L) {
739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 1;
740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (value < 0L) {
742b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 10;
743b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
744b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // ... leaving us with 8 remaining, which we can divide and conquer
745b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int n = 2;
746b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0L << 35)) != 0L) {
747b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      n += 4; value >>>= 28;
748b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
749b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0L << 21)) != 0L) {
750b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      n += 2; value >>>= 14;
751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((value & (~0L << 14)) != 0L) {
753b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      n += 1;
754b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
755b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return n;
756b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
757b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
758b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
759b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
760b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sint64} field.
761b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
762b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSInt64SizeNoTag(final long value) {
763b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt64SizeNoTag(encodeZigZag64(value));
764b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
765b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
766b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
767b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
768b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code fixed64} field.
769b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
770b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
771b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_64_SIZE;
772b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
773b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
774b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
775b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an
776b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code sfixed64} field.
777b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
778b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
779b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_64_SIZE;
780b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
781b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
782b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
783b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
784b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code float} field, including tag.
785b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
786b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
787b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_32_SIZE;
788b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
789b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
790b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
791b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
792b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code double} field, including tag.
793b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
794b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
795b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return FIXED_64_SIZE;
796b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
797b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
798b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
799b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
800b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bool} field.
801b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
802b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) {
803b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return 1;
804b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
805b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
806b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
807b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an enum field.
808b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The provided value is the numeric value used to represent the enum value on the wire
809b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * (not the enum ordinal value).
810b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
811b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeEnumSizeNoTag(final int value) {
812b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeInt32SizeNoTag(value);
813b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
814b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
815b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
816b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
817b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code string} field.
818b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
819b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeStringSizeNoTag(final String value) {
820b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int length;
821b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    try {
822b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      length = Utf8.encodedLength(value);
823b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } catch (UnpairedSurrogateException e) {
824b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // TODO(dweis): Consider using nio Charset methods instead.
825b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final byte[] bytes = value.getBytes(Internal.UTF_8);
826b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      length = bytes.length;
827b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
828b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
829b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(length);
830b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
831b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
832b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
833b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an embedded
834b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * message stored in lazy field.
835b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
836b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
837b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(value.getSerializedSize());
838b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
839b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
840b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
841b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
842b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field.
843b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
844b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeBytesSizeNoTag(final ByteString value) {
845b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(value.size());
846b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
847b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
848b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
849b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
850b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field.
851b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
852b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeByteArraySizeNoTag(final byte[] value) {
853b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(value.length);
854b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
855b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
856b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
857b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
858b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code bytes} field.
859b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
860b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
861b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(value.capacity());
862b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
863b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
864b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
865b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode an embedded
866b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * message field.
867b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
868b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeMessageSizeNoTag(final MessageLite value) {
869b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeLengthDelimitedFieldSize(value.getSerializedSize());
870b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
871b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
872b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static int computeLengthDelimitedFieldSize(int fieldLength) {
873b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt32SizeNoTag(fieldLength) + fieldLength;
874b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
875b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
876b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
877b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
878b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * into values that can be efficiently encoded with varint.  (Otherwise,
879b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * negative values must be sign-extended to 64 bits to be varint encoded,
880b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * thus always taking 10 bytes on the wire.)
881b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
882b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param n A signed 32-bit integer.
883b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @return An unsigned 32-bit integer, stored in a signed int because
884b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *         Java has no explicit unsigned support.
885b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
886b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int encodeZigZag32(final int n) {
887b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Note:  the right-shift must be arithmetic
888b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return (n << 1) ^ (n >> 31);
889b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
890b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
891b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
892b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
893b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * into values that can be efficiently encoded with varint.  (Otherwise,
894b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * negative values must be sign-extended to 64 bits to be varint encoded,
895b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * thus always taking 10 bytes on the wire.)
896b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
897b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param n A signed 64-bit integer.
898b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @return An unsigned 64-bit integer, stored in a signed int because
899b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *         Java has no explicit unsigned support.
900b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
901b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static long encodeZigZag64(final long n) {
902b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Note:  the right-shift must be arithmetic
903b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return (n << 1) ^ (n >> 63);
904b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
905b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
906b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
907b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
908b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
909b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Flushes the stream and forces any buffered bytes to be written.  This
910b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * does not flush the underlying OutputStream.
911b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
912b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract void flush() throws IOException;
913b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
914b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
915b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * If writing to a flat array, return the space left in the array.
916b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Otherwise, throws {@code UnsupportedOperationException}.
917b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
918b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract int spaceLeft();
919b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
920b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
921b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
922b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * a byte array that is exactly big enough to hold a message, then write to
923b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
924b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * after writing verifies that the message was actually as big as expected,
925b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * which can help catch bugs.
926b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
927b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void checkNoSpaceLeft() {
928b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (spaceLeft() != 0) {
929b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw new IllegalStateException("Did not write as much data as expected.");
930b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
931b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
932b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
933b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
934b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * If you create a CodedOutputStream around a simple flat array, you must
935b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * not attempt to write more bytes than the array has space.  Otherwise,
936b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * this exception will be thrown.
937b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
938b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static class OutOfSpaceException extends IOException {
939b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private static final long serialVersionUID = -6947486886997889499L;
940b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
941b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private static final String MESSAGE =
942b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "CodedOutputStream was writing to a flat byte array and ran out of space.";
943b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
944b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    OutOfSpaceException() {
945b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      super(MESSAGE);
946b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
947b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
948b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    OutOfSpaceException(Throwable cause) {
949b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      super(MESSAGE, cause);
950b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
951b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
952b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
953b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
954b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Get the total number of bytes successfully written to this stream.  The
955b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * returned value is not guaranteed to be accurate if exceptions have been
956b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * found in the middle of writing.
957b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
958b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public abstract int getTotalBytesWritten();
959b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
960b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
961b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
962b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /** Write a {@code bytes} field to the stream. Visible for testing. */
963b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length)
964b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException;
965b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
966b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause)
967b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throws IOException {
968b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    logger.log(Level.WARNING,
969b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause);
970b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
971b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Unfortunately there does not appear to be any way to tell Java to encode
972b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // UTF-8 directly into our buffer, so we have to let it create its own byte
973b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // array and then copy.
974b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // TODO(dweis): Consider using nio Charset methods instead.
975b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final byte[] bytes = value.getBytes(Internal.UTF_8);
976b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    try {
977b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(bytes.length);
978b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeLazy(bytes, 0, bytes.length);
979b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } catch (IndexOutOfBoundsException e) {
980b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw new OutOfSpaceException(e);
981b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } catch (OutOfSpaceException e) {
982b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw e;
983b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
984b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
985b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
986b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
987b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
988b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
989b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a {@code group} field, including tag, to the stream.
990b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
991b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated groups are deprecated.
992b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
993b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
994b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException {
995b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
996b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeGroupNoTag(value);
997b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
998b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
999b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1000b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1001b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a {@code group} field to the stream.
1002b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1003b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated groups are deprecated.
1004b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1005b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1006b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeGroupNoTag(final MessageLite value) throws IOException {
1007b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    value.writeTo(this);
1008b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1009b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1010b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1011b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
1012b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code group} field, including tag.
1013b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1014b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated groups are deprecated.
1015b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1016b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1017b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeGroupSize(final int fieldNumber, final MessageLite value) {
1018b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
1019b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1020b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1021b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1022b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a
1023b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code group} field.
1024b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1025b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1026b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeGroupSizeNoTag(final MessageLite value) {
1027b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return value.getSerializedSize();
1028b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1029b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1030b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1031b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Encode and write a varint.  {@code value} is treated as
1032b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * unsigned, so it won't be sign-extended if negative.
1033b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1034b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated use {@link #writeUInt32NoTag} instead.
1035b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1036b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1037b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawVarint32(int value) throws IOException {
1038b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt32NoTag(value);
1039b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1040b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1041b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1042b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Encode and write a varint.
1043b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1044b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated use {@link #writeUInt64NoTag} instead.
1045b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1046b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1047b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawVarint64(long value) throws IOException {
1048b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeUInt64NoTag(value);
1049b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1050b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1051b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1052b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a varint.
1053b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@code value} is treated as unsigned, so it won't be sign-extended if
1054b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * negative.
1055b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1056b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
1057b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1058b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1059b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeRawVarint32Size(final int value) {
1060b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt32SizeNoTag(value);
1061b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1062b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1063b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1064b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Compute the number of bytes that would be needed to encode a varint.
1065b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1066b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead.
1067b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1068b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1069b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int computeRawVarint64Size(long value) {
1070b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return computeUInt64SizeNoTag(value);
1071b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1072b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1073b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1074b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a little-endian 32-bit integer.
1075b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1076b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated Use {@link #writeFixed32NoTag} instead.
1077b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1078b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1079b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawLittleEndian32(final int value) throws IOException {
1080b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed32NoTag(value);
1081b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1082b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1083b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1084b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Write a little-endian 64-bit integer.
1085b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
1086b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @deprecated Use {@link #writeFixed64NoTag} instead.
1087b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1088b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @Deprecated
1089b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public final void writeRawLittleEndian64(final long value) throws IOException {
1090b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    writeFixed64NoTag(value);
1091b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1092b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1093b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // =================================================================
1094b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1095b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1096b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * A {@link CodedOutputStream} that writes directly to a byte array.
1097b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1098b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static class ArrayEncoder extends CodedOutputStream {
1099b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final byte[] buffer;
1100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final int offset;
1101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final int limit;
1102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private int position;
1103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ArrayEncoder(byte[] buffer, int offset, int length) {
1105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (buffer == null) {
1106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new NullPointerException("buffer");
1107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if ((offset | length | (buffer.length - (offset + length))) < 0) {
1109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new IllegalArgumentException(String.format(
1110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            "Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
1111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer.length, offset, length));
1112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.buffer = buffer;
1114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.offset = offset;
1115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      position = offset;
1116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      limit = offset + length;
1117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeTag(final int fieldNumber, final int wireType) throws IOException {
1121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
1122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeInt32(final int fieldNumber, final int value) throws IOException {
1126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeInt32NoTag(value);
1128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeUInt32(final int fieldNumber, final int value) throws IOException {
1132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value);
1134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeFixed32(final int fieldNumber, final int value) throws IOException {
1138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
1139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeFixed32NoTag(value);
1140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeUInt64(final int fieldNumber, final long value) throws IOException {
1144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt64NoTag(value);
1146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeFixed64(final int fieldNumber, final long value) throws IOException {
1150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
1151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeFixed64NoTag(value);
1152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeBool(final int fieldNumber, final boolean value) throws IOException {
1156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write((byte) (value ? 1 : 0));
1158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeString(final int fieldNumber, final String value) throws IOException {
1162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeStringNoTag(value);
1164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
1168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytesNoTag(value);
1170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
1174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArray(fieldNumber, value, 0, value.length);
1175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeByteArray(
1179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int fieldNumber, final byte[] value, final int offset, final int length)
1180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArrayNoTag(value, offset, length);
1183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
1187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.capacity());
1190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeRawBytes(value);
1191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeBytesNoTag(final ByteString value) throws IOException {
1195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.size());
1196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
1197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeByteArrayNoTag(final byte[] value, int offset, int length)
1201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(length);
1203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
1204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeRawBytes(final ByteBuffer value) throws IOException {
1208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value.hasArray()) {
1209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(value.array(), value.arrayOffset(), value.capacity());
1210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ByteBuffer duplicated = value.duplicate();
1212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        duplicated.clear();
1213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(duplicated);
1214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeMessage(final int fieldNumber, final MessageLite value)
1219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessageNoTag(value);
1222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
1226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
1228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
1229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
1230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
1231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
1235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
1237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
1238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
1239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
1240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeMessageNoTag(final MessageLite value) throws IOException {
1244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.getSerializedSize());
1245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
1246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void write(byte value) throws IOException {
1250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = value;
1252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(new IndexOutOfBoundsException(
1254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
1255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeInt32NoTag(int value) throws IOException {
1260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value >= 0) {
1261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt32NoTag(value);
1262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Must sign-extend.
1264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt64NoTag(value);
1265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeUInt32NoTag(int value) throws IOException {
1270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
1271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        long pos = ARRAY_BASE_OFFSET + position;
1272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7F) == 0) {
1274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) value);
1275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position++;
1276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
1279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position++;
1280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        try {
1285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          while (true) {
1286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if ((value & ~0x7F) == 0) {
1287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              buffer[position++] = (byte) value;
1288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              return;
1289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
1290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              buffer[position++] = (byte) ((value & 0x7F) | 0x80);
1291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              value >>>= 7;
1292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
1293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } catch (IndexOutOfBoundsException e) {
1295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          throw new OutOfSpaceException(
1296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              new IndexOutOfBoundsException(
1297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
1298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeFixed32NoTag(int value) throws IOException {
1304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) (value & 0xFF);
1306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((value >> 8) & 0xFF);
1307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((value >> 16) & 0xFF);
1308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((value >> 24) & 0xFF);
1309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(
1311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            new IndexOutOfBoundsException(
1312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
1313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeUInt64NoTag(long value) throws IOException {
1318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
1319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        long pos = ARRAY_BASE_OFFSET + position;
1320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7FL) == 0) {
1322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) value);
1323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position++;
1324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
1327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position++;
1328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        try {
1333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          while (true) {
1334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if ((value & ~0x7FL) == 0) {
1335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              buffer[position++] = (byte) value;
1336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              return;
1337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
1338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
1339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              value >>>= 7;
1340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
1341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } catch (IndexOutOfBoundsException e) {
1343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          throw new OutOfSpaceException(
1344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              new IndexOutOfBoundsException(
1345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
1346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeFixed64NoTag(long value) throws IOException {
1352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value) & 0xFF);
1354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 8) & 0xFF);
1355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 16) & 0xFF);
1356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 24) & 0xFF);
1357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
1358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
1359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
1360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
1361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(
1363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            new IndexOutOfBoundsException(
1364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
1365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void write(byte[] value, int offset, int length) throws IOException {
1370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        System.arraycopy(value, offset, buffer, position, length);
1372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += length;
1373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(
1375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            new IndexOutOfBoundsException(
1376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
1377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeLazy(byte[] value, int offset, int length) throws IOException {
1382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
1383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void write(ByteBuffer value) throws IOException {
1387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int length = value.remaining();
1388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        value.get(buffer, position, length);
1390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += length;
1391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(
1393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            new IndexOutOfBoundsException(
1394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
1395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeLazy(ByteBuffer value) throws IOException {
1400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value);
1401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final void writeStringNoTag(String value) throws IOException {
1405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int oldPosition = position;
1406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
1408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // and at most 3 times of it. We take advantage of this in both branches below.
1409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
1410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
1411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
1412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (minLengthVarIntSize == maxLengthVarIntSize) {
1413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = oldPosition + minLengthVarIntSize;
1414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int newPosition = Utf8.encode(value, buffer, position, spaceLeft());
1415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Since this class is stateful and tracks the position, we rewind and store the state,
1416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // prepend the length, then reset it back to the end of the string.
1417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = oldPosition;
1418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int length = newPosition - oldPosition - minLengthVarIntSize;
1419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeUInt32NoTag(length);
1420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = newPosition;
1421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
1422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int length = Utf8.encodedLength(value);
1423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeUInt32NoTag(length);
1424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = Utf8.encode(value, buffer, position, spaceLeft());
1425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (UnpairedSurrogateException e) {
1427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Roll back the change - we fall back to inefficient path.
1428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position = oldPosition;
1429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // TODO(nathanmittler): We should throw an IOException here instead.
1431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        inefficientWriteStringNoTag(value, e);
1432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void flush() {
1439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Do nothing.
1440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final int spaceLeft() {
1444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return limit - position;
1445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final int getTotalBytesWritten() {
1449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return position - offset;
1450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
1455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * done directly to the underlying array. The buffer position is only updated after a flush.
1456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final class NioHeapEncoder extends ArrayEncoder {
1458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final ByteBuffer byteBuffer;
1459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private int initialPosition;
1460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    NioHeapEncoder(ByteBuffer byteBuffer) {
1462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
1463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          byteBuffer.remaining());
1464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.byteBuffer = byteBuffer;
1465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.initialPosition = byteBuffer.position();
1466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void flush() {
1470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Update the position on the buffer.
1471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      byteBuffer.position(initialPosition + getTotalBytesWritten());
1472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}.
1477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final class NioEncoder extends CodedOutputStream {
1479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final ByteBuffer originalBuffer;
1480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final ByteBuffer buffer;
1481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final int initialPosition;
1482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    NioEncoder(ByteBuffer buffer) {
1484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.originalBuffer = buffer;
1485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
1486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      initialPosition = buffer.position();
1487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
1491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
1492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32(final int fieldNumber, final int value) throws IOException {
1496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeInt32NoTag(value);
1498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
1502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value);
1504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
1508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
1509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeFixed32NoTag(value);
1510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
1514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt64NoTag(value);
1516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
1520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
1521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeFixed64NoTag(value);
1522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
1526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write((byte) (value ? 1 : 0));
1528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeString(final int fieldNumber, final String value) throws IOException {
1532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeStringNoTag(value);
1534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
1538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytesNoTag(value);
1540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
1544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArray(fieldNumber, value, 0, value.length);
1545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(
1549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int fieldNumber, final byte[] value, final int offset, final int length)
1550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArrayNoTag(value, offset, length);
1553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
1557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.capacity());
1560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeRawBytes(value);
1561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessage(final int fieldNumber, final MessageLite value)
1565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
1567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessageNoTag(value);
1568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
1572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
1574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
1575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
1576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
1577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
1581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
1582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
1583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
1584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
1585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
1586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageNoTag(final MessageLite value) throws IOException {
1590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.getSerializedSize());
1591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
1592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte value) throws IOException {
1596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.put(value);
1598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytesNoTag(final ByteString value) throws IOException {
1605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.size());
1606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
1607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
1611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(length);
1612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
1613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawBytes(final ByteBuffer value) throws IOException {
1617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value.hasArray()) {
1618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(value.array(), value.arrayOffset(), value.capacity());
1619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ByteBuffer duplicated = value.duplicate();
1621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        duplicated.clear();
1622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(duplicated);
1623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32NoTag(int value) throws IOException {
1628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value >= 0) {
1629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt32NoTag(value);
1630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Must sign-extend.
1632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt64NoTag(value);
1633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32NoTag(int value) throws IOException {
1638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7F) == 0) {
1641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer.put((byte) value);
1642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer.put((byte) ((value & 0x7F) | 0x80));
1645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32NoTag(int value) throws IOException {
1655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.putInt(value);
1657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64NoTag(long value) throws IOException {
1664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7FL) == 0) {
1667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer.put((byte) value);
1668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer.put((byte) (((int) value & 0x7F) | 0x80));
1671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64NoTag(long value) throws IOException {
1681b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1682b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.putLong(value);
1683b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1684b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1685b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1686b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1687b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1688b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1689b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte[] value, int offset, int length) throws IOException {
1690b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1691b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.put(value, offset, length);
1692b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1693b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1694b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1695b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1696b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1697b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1698b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1700b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(byte[] value, int offset, int length) throws IOException {
1701b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
1702b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1703b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1704b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1705b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(ByteBuffer value) throws IOException {
1706b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1707b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.put(value);
1708b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (BufferOverflowException e) {
1709b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1710b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1711b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(ByteBuffer value) throws IOException {
1715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value);
1716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeStringNoTag(String value) throws IOException {
1720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int startPos = buffer.position();
1721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
1723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // and at most 3 times of it. We take advantage of this in both branches below.
1724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
1725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
1726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
1727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (minLengthVarIntSize == maxLengthVarIntSize) {
1728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Save the current position and increment past the length field. We'll come back
1729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // and write the length field after the encoding is complete.
1730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          final int startOfBytes = buffer.position() + minLengthVarIntSize;
1731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          buffer.position(startOfBytes);
1732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Encode the string.
1734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          encode(value);
1735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Now go back to the beginning and write the length.
1737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int endOfBytes = buffer.position();
1738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          buffer.position(startPos);
1739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeUInt32NoTag(endOfBytes - startOfBytes);
1740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Reposition the buffer past the written data.
1742b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          buffer.position(endOfBytes);
1743b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
1744b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          final int length = Utf8.encodedLength(value);
1745b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeUInt32NoTag(length);
1746b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          encode(value);
1747b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1748b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (UnpairedSurrogateException e) {
1749b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Roll back the change and convert to an IOException.
1750b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        buffer.position(startPos);
1751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // TODO(nathanmittler): We should throw an IOException here instead.
1753b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        inefficientWriteStringNoTag(value, e);
1754b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IllegalArgumentException e) {
1755b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Thrown by buffer.position() if out of range.
1756b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1757b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1758b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1759b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1760b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1761b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void flush() {
1762b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Update the position of the original buffer.
1763b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      originalBuffer.position(buffer.position());
1764b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1765b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1766b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1767b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public int spaceLeft() {
1768b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return buffer.remaining();
1769b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1770b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1771b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1772b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public int getTotalBytesWritten() {
1773b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return buffer.position() - initialPosition;
1774b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1775b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1776b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void encode(String value) throws IOException {
1777b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
1778b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Utf8.encodeUtf8(value, buffer);
1779b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
1780b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
1781b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1782b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1783b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1784b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1785b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1786b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Abstract base class for buffered encoders.
1787b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1788b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
1789b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final byte[] buffer;
1790b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final int limit;
1791b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int position;
1792b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int totalBytesWritten;
1793b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1794b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    AbstractBufferedEncoder(int bufferSize) {
1795b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (bufferSize < 0) {
1796b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new IllegalArgumentException("bufferSize must be >= 0");
1797b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1798b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // As an optimization, we require that the buffer be able to store at least 2
1799b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // varints so that we can buffer any integer write (tag + value). This reduces the
1800b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // number of range checks for a single write to 1 (i.e. if there is not enough space
1801b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // to buffer the tag+value, flush and then buffer it).
1802b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)];
1803b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.limit = buffer.length;
1804b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1805b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1806b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1807b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final int spaceLeft() {
1808b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw new UnsupportedOperationException(
1809b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          "spaceLeft() can only be called on CodedOutputStreams that are "
1810b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              + "writing to a flat array or ByteBuffer.");
1811b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1812b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1813b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1814b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public final int getTotalBytesWritten() {
1815b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return totalBytesWritten;
1816b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1817b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1818b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1819b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1820b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1821b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1822b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void buffer(byte value) {
1823b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = value;
1824b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten++;
1825b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1826b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1827b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1828b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1829b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1830b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1831b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferTag(final int fieldNumber, final int wireType) {
1832b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
1833b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1834b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1835b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1836b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1837b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1838b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1839b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferInt32NoTag(final int value) {
1840b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value >= 0) {
1841b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        bufferUInt32NoTag(value);
1842b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1843b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Must sign-extend.
1844b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        bufferUInt64NoTag(value);
1845b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1846b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1847b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1848b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1849b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1850b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1851b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1852b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferUInt32NoTag(int value) {
1853b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
1854b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final long originalPos = ARRAY_BASE_OFFSET + position;
1855b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        long pos = originalPos;
1856b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1857b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7F) == 0) {
1858b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) value);
1859b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            break;
1860b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1861b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
1862b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1863b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1864b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1865b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int delta = (int) (pos - originalPos);
1866b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += delta;
1867b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += delta;
1868b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1869b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1870b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7F) == 0) {
1871b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer[position++] = (byte) value;
1872b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            totalBytesWritten++;
1873b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1874b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1875b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer[position++] = (byte) ((value & 0x7F) | 0x80);
1876b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            totalBytesWritten++;
1877b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1878b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1879b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1880b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1881b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1882b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1883b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1884b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1885b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1886b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1887b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferUInt64NoTag(long value) {
1888b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
1889b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final long originalPos = ARRAY_BASE_OFFSET + position;
1890b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        long pos = originalPos;
1891b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1892b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7FL) == 0) {
1893b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) value);
1894b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            break;
1895b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1896b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
1897b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1898b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1899b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1900b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int delta = (int) (pos - originalPos);
1901b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += delta;
1902b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += delta;
1903b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
1904b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (true) {
1905b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if ((value & ~0x7FL) == 0) {
1906b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer[position++] = (byte) value;
1907b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            totalBytesWritten++;
1908b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return;
1909b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
1910b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
1911b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            totalBytesWritten++;
1912b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            value >>>= 7;
1913b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
1914b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
1915b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1916b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1917b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1918b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1919b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1920b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1921b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1922b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferFixed32NoTag(int value) {
1923b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) (value & 0xFF);
1924b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 8) & 0xFF);
1925b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 16) & 0xFF);
1926b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 24) & 0xFF);
1927b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += FIXED_32_SIZE;
1928b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1929b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1930b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
1931b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * This method does not perform bounds checking on the array. Checking array bounds is the
1932b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * responsibility of the caller.
1933b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
1934b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final void bufferFixed64NoTag(long value) {
1935b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) (value & 0xFF);
1936b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 8) & 0xFF);
1937b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 16) & 0xFF);
1938b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((value >> 24) & 0xFF);
1939b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
1940b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
1941b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
1942b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
1943b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += FIXED_64_SIZE;
1944b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1945b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1946b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1947b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
1948b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to
1949b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * support string encoding operations. All other writes are just passed through to the
1950b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * {@link ByteOutput}.
1951b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
1952b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final class ByteOutputEncoder extends AbstractBufferedEncoder {
1953b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final ByteOutput out;
1954b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1955b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ByteOutputEncoder(ByteOutput out, int bufferSize) {
1956b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      super(bufferSize);
1957b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (out == null) {
1958b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new NullPointerException("out");
1959b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1960b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.out = out;
1961b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1962b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1963b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1964b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
1965b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
1966b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1967b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1968b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1969b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32(final int fieldNumber, final int value) throws IOException {
1970b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
1971b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1972b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferInt32NoTag(value);
1973b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1974b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1975b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1976b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
1977b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
1978b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1979b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt32NoTag(value);
1980b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1981b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1982b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1983b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
1984b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
1985b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
1986b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed32NoTag(value);
1987b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1988b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1989b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1990b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
1991b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
1992b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
1993b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt64NoTag(value);
1994b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1995b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1996b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
1997b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
1998b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
1999b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
2000b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed64NoTag(value);
2001b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2002b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2003b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2004b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
2005b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
2006b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
2007b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer((byte) (value ? 1 : 0));
2008b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2009b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2010b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2011b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeString(final int fieldNumber, final String value) throws IOException {
2012b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2013b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeStringNoTag(value);
2014b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2015b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2016b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2017b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
2018b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2019b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytesNoTag(value);
2020b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2021b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2022b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2023b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
2024b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArray(fieldNumber, value, 0, value.length);
2025b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2026b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2027b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2028b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(
2029b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int fieldNumber, final byte[] value, final int offset, final int length)
2030b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2031b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2032b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArrayNoTag(value, offset, length);
2033b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2034b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2035b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2036b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
2037b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2038b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2039b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.capacity());
2040b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeRawBytes(value);
2041b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2042b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2043b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2044b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytesNoTag(final ByteString value) throws IOException {
2045b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.size());
2046b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
2047b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2048b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2049b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2050b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
2051b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(length);
2052b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
2053b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2054b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2055b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2056b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawBytes(final ByteBuffer value) throws IOException {
2057b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value.hasArray()) {
2058b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(value.array(), value.arrayOffset(), value.capacity());
2059b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2060b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ByteBuffer duplicated = value.duplicate();
2061b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        duplicated.clear();
2062b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(duplicated);
2063b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2064b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2065b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2066b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2067b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessage(final int fieldNumber, final MessageLite value)
2068b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2069b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2070b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessageNoTag(value);
2071b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2072b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2073b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2074b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
2075b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2076b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
2077b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
2078b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
2079b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
2080b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2081b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2082b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2083b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
2084b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2085b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
2086b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
2087b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
2088b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
2089b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2090b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2091b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2092b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageNoTag(final MessageLite value) throws IOException {
2093b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.getSerializedSize());
2094b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
2095b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2096b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2097b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2098b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte value) throws IOException {
2099b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (position == limit) {
2100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer(value);
2104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32NoTag(int value) throws IOException {
2108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value >= 0) {
2109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt32NoTag(value);
2110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Must sign-extend.
2112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt64NoTag(value);
2113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32NoTag(int value) throws IOException {
2118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE);
2119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt32NoTag(value);
2120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32NoTag(final int value) throws IOException {
2124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(FIXED_32_SIZE);
2125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed32NoTag(value);
2126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64NoTag(long value) throws IOException {
2130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE);
2131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt64NoTag(value);
2132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64NoTag(final long value) throws IOException {
2136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(FIXED_64_SIZE);
2137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed64NoTag(value);
2138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeStringNoTag(String value) throws IOException {
2142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
2143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // and at most 3 times of it. We take advantage of this in both branches below.
2144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
2145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
2146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // If we are streaming and the potential length is too big to fit in our buffer, we take the
2148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // slower path.
2149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (maxLengthVarIntSize + maxLength > limit) {
2150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
2151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // does the same internally and then does *another copy* to return a byte[] of exactly the
2152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
2153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // UTF-8 encoded bytes.
2154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final byte[] encodedBytes = new byte[maxLength];
2155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
2156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt32NoTag(actualLength);
2157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeLazy(encodedBytes, 0, actualLength);
2158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return;
2159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Fast path: we have enough space available in our buffer for the string...
2162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (maxLengthVarIntSize + maxLength > limit - position) {
2163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Flush to free up space.
2164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      final int oldPosition = position;
2168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
2169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Optimize for the case where we know this length results in a constant varint length as
2170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // this saves a pass for measuring the length of the string.
2171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
2172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (minLengthVarIntSize == maxLengthVarIntSize) {
2174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = oldPosition + minLengthVarIntSize;
2175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int newPosition = Utf8.encode(value, buffer, position, limit - position);
2176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Since this class is stateful and tracks the position, we rewind and store the state,
2177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // prepend the length, then reset it back to the end of the string.
2178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = oldPosition;
2179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int length = newPosition - oldPosition - minLengthVarIntSize;
2180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          bufferUInt32NoTag(length);
2181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = newPosition;
2182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          totalBytesWritten += length;
2183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
2184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int length = Utf8.encodedLength(value);
2185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          bufferUInt32NoTag(length);
2186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = Utf8.encode(value, buffer, position, length);
2187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          totalBytesWritten += length;
2188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (UnpairedSurrogateException e) {
2190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Roll back the change and convert to an IOException.
2191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten -= position - oldPosition;
2192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position = oldPosition;
2193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // TODO(nathanmittler): We should throw an IOException here instead.
2195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        inefficientWriteStringNoTag(value, e);
2196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (IndexOutOfBoundsException e) {
2197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new OutOfSpaceException(e);
2198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void flush() throws IOException {
2203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (position > 0) {
2204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Flush the buffer.
2205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte[] value, int offset, int length) throws IOException {
2211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flush();
2212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.write(value, offset, length);
2213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += length;
2214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(byte[] value, int offset, int length) throws IOException {
2218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flush();
2219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.writeLazy(value, offset, length);
2220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += length;
2221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(ByteBuffer value) throws IOException {
2225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flush();
2226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int length = value.remaining();
2227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.write(value);
2228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += length;
2229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(ByteBuffer value) throws IOException {
2233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flush();
2234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int length = value.remaining();
2235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.writeLazy(value);
2236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      totalBytesWritten += length;
2237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void flushIfNotAvailable(int requiredSize) throws IOException {
2240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (limit - position < requiredSize) {
2241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void doFlush() throws IOException {
2246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.write(buffer, 0, position);
2247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      position = 0;
2248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
2250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
2252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal
2253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * buffering to optimize writes to the {@link OutputStream}.
2254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
2255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static final class OutputStreamEncoder extends AbstractBufferedEncoder {
2256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private final OutputStream out;
2257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    OutputStreamEncoder(OutputStream out, int bufferSize) {
2259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      super(bufferSize);
2260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (out == null) {
2261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new NullPointerException("out");
2262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      this.out = out;
2264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
2268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
2269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32(final int fieldNumber, final int value) throws IOException {
2273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
2274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
2275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferInt32NoTag(value);
2276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
2280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
2281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
2282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt32NoTag(value);
2283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
2287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
2288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
2289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed32NoTag(value);
2290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
2294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
2295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
2296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt64NoTag(value);
2297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
2301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
2302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
2303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed64NoTag(value);
2304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
2308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
2309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
2310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer((byte) (value ? 1 : 0));
2311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeString(final int fieldNumber, final String value) throws IOException {
2315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeStringNoTag(value);
2317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
2321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytesNoTag(value);
2323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
2327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArray(fieldNumber, value, 0, value.length);
2328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArray(
2332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int fieldNumber, final byte[] value, final int offset, final int length)
2333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeByteArrayNoTag(value, offset, length);
2336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
2340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.capacity());
2343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeRawBytes(value);
2344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeBytesNoTag(final ByteString value) throws IOException {
2348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.size());
2349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
2350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
2354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(length);
2355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
2356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawBytes(final ByteBuffer value) throws IOException {
2360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value.hasArray()) {
2361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(value.array(), value.arrayOffset(), value.capacity());
2362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ByteBuffer duplicated = value.duplicate();
2364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        duplicated.clear();
2365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        write(duplicated);
2366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessage(final int fieldNumber, final MessageLite value)
2371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
2373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessageNoTag(value);
2374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
2378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
2380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
2381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
2382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
2383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
2387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
2389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
2390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
2391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
2392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeMessageNoTag(final MessageLite value) throws IOException {
2396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      writeUInt32NoTag(value.getSerializedSize());
2397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value.writeTo(this);
2398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte value) throws IOException {
2402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (position == limit) {
2403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      buffer(value);
2407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeInt32NoTag(int value) throws IOException {
2411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (value >= 0) {
2412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt32NoTag(value);
2413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Must sign-extend.
2415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        writeUInt64NoTag(value);
2416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt32NoTag(int value) throws IOException {
2421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE);
2422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt32NoTag(value);
2423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed32NoTag(final int value) throws IOException {
2427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(FIXED_32_SIZE);
2428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed32NoTag(value);
2429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeUInt64NoTag(long value) throws IOException {
2433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(MAX_VARINT_SIZE);
2434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferUInt64NoTag(value);
2435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeFixed64NoTag(final long value) throws IOException {
2439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      flushIfNotAvailable(FIXED_64_SIZE);
2440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bufferFixed64NoTag(value);
2441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeStringNoTag(String value) throws IOException {
2445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
2446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
2447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // and at most 3 times of it. We take advantage of this in both branches below.
2448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
2449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
2450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // If we are streaming and the potential length is too big to fit in our buffer, we take the
2452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // slower path.
2453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (maxLengthVarIntSize + maxLength > limit) {
2454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
2455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // does the same internally and then does *another copy* to return a byte[] of exactly the
2456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
2457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // UTF-8 encoded bytes.
2458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          final byte[] encodedBytes = new byte[maxLength];
2459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
2460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeUInt32NoTag(actualLength);
2461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          writeLazy(encodedBytes, 0, actualLength);
2462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          return;
2463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Fast path: we have enough space available in our buffer for the string...
2466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (maxLengthVarIntSize + maxLength > limit - position) {
2467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Flush to free up space.
2468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          doFlush();
2469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Optimize for the case where we know this length results in a constant varint length as
2472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // this saves a pass for measuring the length of the string.
2473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
2474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int oldPosition = position;
2475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int length;
2476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        try {
2477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          if (minLengthVarIntSize == maxLengthVarIntSize) {
2478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position = oldPosition + minLengthVarIntSize;
2479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            int newPosition = Utf8.encode(value, buffer, position, limit - position);
2480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            // Since this class is stateful and tracks the position, we rewind and store the
2481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            // state, prepend the length, then reset it back to the end of the string.
2482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position = oldPosition;
2483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            length = newPosition - oldPosition - minLengthVarIntSize;
2484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            bufferUInt32NoTag(length);
2485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position = newPosition;
2486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          } else {
2487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            length = Utf8.encodedLength(value);
2488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            bufferUInt32NoTag(length);
2489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            position = Utf8.encode(value, buffer, position, length);
2490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
2491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          totalBytesWritten += length;
2492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } catch (UnpairedSurrogateException e) {
2493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Be extra careful and restore the original position for retrying the write with the
2494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // less efficient path.
2495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          totalBytesWritten -= position - oldPosition;
2496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = oldPosition;
2497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          throw e;
2498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } catch (ArrayIndexOutOfBoundsException e) {
2499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          throw new OutOfSpaceException(e);
2500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (UnpairedSurrogateException e) {
2502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        inefficientWriteStringNoTag(value, e);
2503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void flush() throws IOException {
2508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (position > 0) {
2509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Flush the buffer.
2510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(byte[] value, int offset, int length)
2516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throws IOException {
2517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (limit - position >= length) {
2518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // We have room in the current buffer.
2519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        System.arraycopy(value, offset, buffer, position, length);
2520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += length;
2521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += length;
2522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Write extends past current buffer.  Fill the rest of this buffer and
2524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // flush.
2525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int bytesWritten = limit - position;
2526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        System.arraycopy(value, offset, buffer, position, bytesWritten);
2527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        offset += bytesWritten;
2528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        length -= bytesWritten;
2529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position = limit;
2530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += bytesWritten;
2531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Now deal with the rest.
2534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Since we have an output stream, this is our buffer
2535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // and buffer offset == 0
2536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (length <= limit) {
2537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Fits in new buffer.
2538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          System.arraycopy(value, offset, buffer, 0, length);
2539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          position = length;
2540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
2541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Write is very big.  Let's do it all at once.
2542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          out.write(value, offset, length);
2543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += length;
2545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(byte[] value, int offset, int length) throws IOException {
2550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value, offset, length);
2551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void write(ByteBuffer value) throws IOException {
2555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int length = value.remaining();
2556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (limit - position >= length) {
2557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // We have room in the current buffer.
2558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        value.get(buffer, position, length);
2559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position += length;
2560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += length;
2561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
2562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Write extends past current buffer.  Fill the rest of this buffer and
2563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // flush.
2564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final int bytesWritten = limit - position;
2565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        value.get(buffer, position, bytesWritten);
2566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        length -= bytesWritten;
2567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position = limit;
2568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += bytesWritten;
2569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Now deal with the rest.
2572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Since we have an output stream, this is our buffer
2573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // and buffer offset == 0
2574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        while (length > limit) {
2575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // Copy data into the buffer before writing it to OutputStream.
2576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          value.get(buffer, 0, limit);
2577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          out.write(buffer, 0, limit);
2578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          length -= limit;
2579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          totalBytesWritten += limit;
2580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        value.get(buffer, 0, length);
2582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        position = length;
2583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        totalBytesWritten += length;
2584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @Override
2588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public void writeLazy(ByteBuffer value) throws IOException {
2589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      write(value);
2590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void flushIfNotAvailable(int requiredSize) throws IOException {
2593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (limit - position < requiredSize) {
2594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        doFlush();
2595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void doFlush() throws IOException {
2599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      out.write(buffer, 0, position);
2600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      position = 0;
2601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
2603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
2605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
2606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * platform.
2607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
2608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static sun.misc.Unsafe getUnsafe() {
2609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sun.misc.Unsafe unsafe = null;
2610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    try {
2611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
2612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        @Override
2613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        public sun.misc.Unsafe run() throws Exception {
2614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
2615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          for (Field f : k.getDeclaredFields()) {
2617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            f.setAccessible(true);
2618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            Object x = f.get(null);
2619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (k.isInstance(x)) {
2620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              return k.cast(x);
2621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
2622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          }
2623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          // The sun.misc.Unsafe field does not exist.
2624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          return null;
2625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
2626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      });
2627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } catch (Throwable e) {
2628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
2629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // for Unsafe.
2630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
2633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        unsafe != null ? "available" : "unavailable");
2634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return unsafe;
2635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
2636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
2638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Indicates whether or not unsafe array operations are supported on this platform.
2639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
2640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(nathanmittler): Add support for Android's MemoryBlock.
2641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static boolean supportsUnsafeArrayOperations() {
2642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    boolean supported = false;
2643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (UNSAFE != null) {
2644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      try {
2645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
2646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
2647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        supported = true;
2648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } catch (Throwable e) {
2649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Do nothing.
2650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
2651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
2652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    logger.log(Level.FINEST, "Unsafe array operations: {}",
2653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        supported ? "available" : "unavailable");
2654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return supported;
2655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
2656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
2657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
2658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
2659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * available.
2660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
2661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static <T> int byteArrayBaseOffset() {
2662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
2663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
2664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
2665