• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2013 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf.nano;
32 
33 import java.io.IOException;
34 import java.nio.BufferOverflowException;
35 import java.nio.ByteBuffer;
36 import java.nio.ByteOrder;
37 import java.nio.ReadOnlyBufferException;
38 
39 /**
40  * Encodes and writes protocol message fields.
41  *
42  * <p>This class contains two kinds of methods:  methods that write specific
43  * protocol message constructs and field types (e.g. {@link #writeTag} and
44  * {@link #writeInt32}) and methods that write low-level values (e.g.
45  * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
46  * writing encoded protocol messages, you should use the former methods, but if
47  * you are writing some other format of your own design, use the latter.
48  *
49  * <p>This class is totally unsynchronized.
50  *
51  * @author kneton@google.com Kenton Varda
52  */
53 public final class CodedOutputByteBufferNano {
54   /* max bytes per java UTF-16 char in UTF-8 */
55   private static final int MAX_UTF8_EXPANSION = 3;
56   private final ByteBuffer buffer;
57 
CodedOutputByteBufferNano(final byte[] buffer, final int offset, final int length)58   private CodedOutputByteBufferNano(final byte[] buffer, final int offset,
59                             final int length) {
60     this(ByteBuffer.wrap(buffer, offset, length));
61   }
62 
CodedOutputByteBufferNano(final ByteBuffer buffer)63   private CodedOutputByteBufferNano(final ByteBuffer buffer) {
64     this.buffer = buffer;
65     this.buffer.order(ByteOrder.LITTLE_ENDIAN);
66   }
67 
68   /**
69    * Create a new {@code CodedOutputStream} that writes directly to the given
70    * byte array.  If more bytes are written than fit in the array,
71    * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
72    * array is faster than writing to an {@code OutputStream}.
73    */
newInstance(final byte[] flatArray)74   public static CodedOutputByteBufferNano newInstance(final byte[] flatArray) {
75     return newInstance(flatArray, 0, flatArray.length);
76   }
77 
78   /**
79    * Create a new {@code CodedOutputStream} that writes directly to the given
80    * byte array slice.  If more bytes are written than fit in the slice,
81    * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
82    * array is faster than writing to an {@code OutputStream}.
83    */
newInstance(final byte[] flatArray, final int offset, final int length)84   public static CodedOutputByteBufferNano newInstance(final byte[] flatArray,
85                                               final int offset,
86                                               final int length) {
87     return new CodedOutputByteBufferNano(flatArray, offset, length);
88   }
89 
90   // -----------------------------------------------------------------
91 
92   /** Write a {@code double} field, including tag, to the stream. */
writeDouble(final int fieldNumber, final double value)93   public void writeDouble(final int fieldNumber, final double value)
94                           throws IOException {
95     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
96     writeDoubleNoTag(value);
97   }
98 
99   /** Write a {@code float} field, including tag, to the stream. */
writeFloat(final int fieldNumber, final float value)100   public void writeFloat(final int fieldNumber, final float value)
101                          throws IOException {
102     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
103     writeFloatNoTag(value);
104   }
105 
106   /** Write a {@code uint64} field, including tag, to the stream. */
writeUInt64(final int fieldNumber, final long value)107   public void writeUInt64(final int fieldNumber, final long value)
108                           throws IOException {
109     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
110     writeUInt64NoTag(value);
111   }
112 
113   /** Write an {@code int64} field, including tag, to the stream. */
writeInt64(final int fieldNumber, final long value)114   public void writeInt64(final int fieldNumber, final long value)
115                          throws IOException {
116     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
117     writeInt64NoTag(value);
118   }
119 
120   /** Write an {@code int32} field, including tag, to the stream. */
writeInt32(final int fieldNumber, final int value)121   public void writeInt32(final int fieldNumber, final int value)
122                          throws IOException {
123     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
124     writeInt32NoTag(value);
125   }
126 
127   /** Write a {@code fixed64} field, including tag, to the stream. */
writeFixed64(final int fieldNumber, final long value)128   public void writeFixed64(final int fieldNumber, final long value)
129                            throws IOException {
130     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
131     writeFixed64NoTag(value);
132   }
133 
134   /** Write a {@code fixed32} field, including tag, to the stream. */
writeFixed32(final int fieldNumber, final int value)135   public void writeFixed32(final int fieldNumber, final int value)
136                            throws IOException {
137     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
138     writeFixed32NoTag(value);
139   }
140 
141   /** Write a {@code bool} field, including tag, to the stream. */
writeBool(final int fieldNumber, final boolean value)142   public void writeBool(final int fieldNumber, final boolean value)
143                         throws IOException {
144     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
145     writeBoolNoTag(value);
146   }
147 
148   /** Write a {@code string} field, including tag, to the stream. */
writeString(final int fieldNumber, final String value)149   public void writeString(final int fieldNumber, final String value)
150                           throws IOException {
151     writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
152     writeStringNoTag(value);
153   }
154 
155   /** Write a {@code group} field, including tag, to the stream. */
writeGroup(final int fieldNumber, final MessageNano value)156   public void writeGroup(final int fieldNumber, final MessageNano value)
157                          throws IOException {
158     writeTag(fieldNumber, WireFormatNano.WIRETYPE_START_GROUP);
159     writeGroupNoTag(value);
160     writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
161   }
162 
163   /** Write an embedded message field, including tag, to the stream. */
writeMessage(final int fieldNumber, final MessageNano value)164   public void writeMessage(final int fieldNumber, final MessageNano value)
165                            throws IOException {
166     writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
167     writeMessageNoTag(value);
168   }
169 
170   /** Write a {@code bytes} field, including tag, to the stream. */
writeBytes(final int fieldNumber, final byte[] value)171   public void writeBytes(final int fieldNumber, final byte[] value)
172                          throws IOException {
173     writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
174     writeBytesNoTag(value);
175   }
176 
177   /** Write a {@code uint32} field, including tag, to the stream. */
writeUInt32(final int fieldNumber, final int value)178   public void writeUInt32(final int fieldNumber, final int value)
179                           throws IOException {
180     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
181     writeUInt32NoTag(value);
182   }
183 
184   /**
185    * Write an enum field, including tag, to the stream.  Caller is responsible
186    * for converting the enum value to its numeric value.
187    */
writeEnum(final int fieldNumber, final int value)188   public void writeEnum(final int fieldNumber, final int value)
189                         throws IOException {
190     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
191     writeEnumNoTag(value);
192   }
193 
194   /** Write an {@code sfixed32} field, including tag, to the stream. */
writeSFixed32(final int fieldNumber, final int value)195   public void writeSFixed32(final int fieldNumber, final int value)
196                             throws IOException {
197     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
198     writeSFixed32NoTag(value);
199   }
200 
201   /** Write an {@code sfixed64} field, including tag, to the stream. */
writeSFixed64(final int fieldNumber, final long value)202   public void writeSFixed64(final int fieldNumber, final long value)
203                             throws IOException {
204     writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
205     writeSFixed64NoTag(value);
206   }
207 
208   /** Write an {@code sint32} field, including tag, to the stream. */
writeSInt32(final int fieldNumber, final int value)209   public void writeSInt32(final int fieldNumber, final int value)
210                           throws IOException {
211     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
212     writeSInt32NoTag(value);
213   }
214 
215   /** Write an {@code sint64} field, including tag, to the stream. */
writeSInt64(final int fieldNumber, final long value)216   public void writeSInt64(final int fieldNumber, final long value)
217                           throws IOException {
218     writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
219     writeSInt64NoTag(value);
220   }
221 
222   /**
223    * Write a MessageSet extension field to the stream.  For historical reasons,
224    * the wire format differs from normal fields.
225    */
226 //  public void writeMessageSetExtension(final int fieldNumber,
227 //                                       final MessageMicro value)
228 //                                       throws IOException {
229 //    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
230 //    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
231 //    writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
232 //    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
233 //  }
234 
235   /**
236    * Write an unparsed MessageSet extension field to the stream.  For
237    * historical reasons, the wire format differs from normal fields.
238    */
239 //  public void writeRawMessageSetExtension(final int fieldNumber,
240 //                                          final ByteStringMicro value)
241 //                                          throws IOException {
242 //    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
243 //    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
244 //    writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
245 //    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
246 //  }
247 
248   // -----------------------------------------------------------------
249 
250   /** Write a {@code double} field to the stream. */
writeDoubleNoTag(final double value)251   public void writeDoubleNoTag(final double value) throws IOException {
252     writeRawLittleEndian64(Double.doubleToLongBits(value));
253   }
254 
255   /** Write a {@code float} field to the stream. */
writeFloatNoTag(final float value)256   public void writeFloatNoTag(final float value) throws IOException {
257     writeRawLittleEndian32(Float.floatToIntBits(value));
258   }
259 
260   /** Write a {@code uint64} field to the stream. */
writeUInt64NoTag(final long value)261   public void writeUInt64NoTag(final long value) throws IOException {
262     writeRawVarint64(value);
263   }
264 
265   /** Write an {@code int64} field to the stream. */
writeInt64NoTag(final long value)266   public void writeInt64NoTag(final long value) throws IOException {
267     writeRawVarint64(value);
268   }
269 
270   /** Write an {@code int32} field to the stream. */
writeInt32NoTag(final int value)271   public void writeInt32NoTag(final int value) throws IOException {
272     if (value >= 0) {
273       writeRawVarint32(value);
274     } else {
275       // Must sign-extend.
276       writeRawVarint64(value);
277     }
278   }
279 
280   /** Write a {@code fixed64} field to the stream. */
writeFixed64NoTag(final long value)281   public void writeFixed64NoTag(final long value) throws IOException {
282     writeRawLittleEndian64(value);
283   }
284 
285   /** Write a {@code fixed32} field to the stream. */
writeFixed32NoTag(final int value)286   public void writeFixed32NoTag(final int value) throws IOException {
287     writeRawLittleEndian32(value);
288   }
289 
290   /** Write a {@code bool} field to the stream. */
writeBoolNoTag(final boolean value)291   public void writeBoolNoTag(final boolean value) throws IOException {
292     writeRawByte(value ? 1 : 0);
293   }
294 
295   /** Write a {@code string} field to the stream. */
writeStringNoTag(final String value)296   public void writeStringNoTag(final String value) throws IOException {
297     // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
298     // and at most 3 times of it. Optimize for the case where we know this length results in a
299     // constant varint length - saves measuring length of the string.
300     try {
301       final int minLengthVarIntSize = computeRawVarint32Size(value.length());
302       final int maxLengthVarIntSize = computeRawVarint32Size(value.length() * MAX_UTF8_EXPANSION);
303       if (minLengthVarIntSize == maxLengthVarIntSize) {
304         int oldPosition = buffer.position();
305         // Buffer.position, when passed a position that is past its limit, throws
306         // IllegalArgumentException, and this class is documented to throw
307         // OutOfSpaceException instead.
308         if (buffer.remaining() < minLengthVarIntSize) {
309           throw new OutOfSpaceException(oldPosition + minLengthVarIntSize, buffer.limit());
310         }
311         buffer.position(oldPosition + minLengthVarIntSize);
312         encode(value, buffer);
313         int newPosition = buffer.position();
314         buffer.position(oldPosition);
315         writeRawVarint32(newPosition - oldPosition - minLengthVarIntSize);
316         buffer.position(newPosition);
317       } else {
318         writeRawVarint32(encodedLength(value));
319         encode(value, buffer);
320       }
321     } catch (BufferOverflowException e) {
322       final OutOfSpaceException outOfSpaceException = new OutOfSpaceException(buffer.position(),
323           buffer.limit());
324       outOfSpaceException.initCause(e);
325       throw outOfSpaceException;
326     }
327   }
328 
329   // These UTF-8 handling methods are copied from Guava's Utf8 class.
330   /**
331    * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
332    * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
333    * both time and space.
334    *
335    * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
336    *     surrogates)
337    */
encodedLength(CharSequence sequence)338   private static int encodedLength(CharSequence sequence) {
339     // Warning to maintainers: this implementation is highly optimized.
340     int utf16Length = sequence.length();
341     int utf8Length = utf16Length;
342     int i = 0;
343 
344     // This loop optimizes for pure ASCII.
345     while (i < utf16Length && sequence.charAt(i) < 0x80) {
346       i++;
347     }
348 
349     // This loop optimizes for chars less than 0x800.
350     for (; i < utf16Length; i++) {
351       char c = sequence.charAt(i);
352       if (c < 0x800) {
353         utf8Length += ((0x7f - c) >>> 31);  // branch free!
354       } else {
355         utf8Length += encodedLengthGeneral(sequence, i);
356         break;
357       }
358     }
359 
360     if (utf8Length < utf16Length) {
361       // Necessary and sufficient condition for overflow because of maximum 3x expansion
362       throw new IllegalArgumentException("UTF-8 length does not fit in int: "
363               + (utf8Length + (1L << 32)));
364     }
365     return utf8Length;
366   }
367 
encodedLengthGeneral(CharSequence sequence, int start)368   private static int encodedLengthGeneral(CharSequence sequence, int start) {
369     int utf16Length = sequence.length();
370     int utf8Length = 0;
371     for (int i = start; i < utf16Length; i++) {
372       char c = sequence.charAt(i);
373       if (c < 0x800) {
374         utf8Length += (0x7f - c) >>> 31; // branch free!
375       } else {
376         utf8Length += 2;
377         // jdk7+: if (Character.isSurrogate(c)) {
378         if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
379           // Check that we have a well-formed surrogate pair.
380           int cp = Character.codePointAt(sequence, i);
381           if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
382             throw new IllegalArgumentException("Unpaired surrogate at index " + i);
383           }
384           i++;
385         }
386       }
387     }
388     return utf8Length;
389   }
390 
391   /**
392    * Encodes {@code sequence} into UTF-8, in {@code byteBuffer}. For a string, this method is
393    * equivalent to {@code buffer.put(string.getBytes(UTF_8))}, but is more efficient in both time
394    * and space. Bytes are written starting at the current position. This method requires paired
395    * surrogates, and therefore does not support chunking.
396    *
397    * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
398    * compute the exact amount needed, or leave room for {@code 3 * sequence.length()}, which is the
399    * largest possible number of bytes that any input can be encoded to.
400    *
401    * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
402    *     surrogates)
403    * @throws BufferOverflowException if {@code sequence} encoded in UTF-8 does not fit in
404    *     {@code byteBuffer}'s remaining space.
405    * @throws ReadOnlyBufferException if {@code byteBuffer} is a read-only buffer.
406    */
encode(CharSequence sequence, ByteBuffer byteBuffer)407   private static void encode(CharSequence sequence, ByteBuffer byteBuffer) {
408     if (byteBuffer.isReadOnly()) {
409       throw new ReadOnlyBufferException();
410     } else if (byteBuffer.hasArray()) {
411       try {
412         int encoded = encode(sequence,
413                 byteBuffer.array(),
414                 byteBuffer.arrayOffset() + byteBuffer.position(),
415                 byteBuffer.remaining());
416         byteBuffer.position(encoded - byteBuffer.arrayOffset());
417       } catch (ArrayIndexOutOfBoundsException e) {
418         BufferOverflowException boe = new BufferOverflowException();
419         boe.initCause(e);
420         throw boe;
421       }
422     } else {
423       encodeDirect(sequence, byteBuffer);
424     }
425   }
426 
encodeDirect(CharSequence sequence, ByteBuffer byteBuffer)427   private static void encodeDirect(CharSequence sequence, ByteBuffer byteBuffer) {
428     int utf16Length = sequence.length();
429     for (int i = 0; i < utf16Length; i++) {
430       final char c = sequence.charAt(i);
431       if (c < 0x80) { // ASCII
432         byteBuffer.put((byte) c);
433       } else if (c < 0x800) { // 11 bits, two UTF-8 bytes
434         byteBuffer.put((byte) ((0xF << 6) | (c >>> 6)));
435         byteBuffer.put((byte) (0x80 | (0x3F & c)));
436       } else if (c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) {
437         // Maximium single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
438         byteBuffer.put((byte) ((0xF << 5) | (c >>> 12)));
439         byteBuffer.put((byte) (0x80 | (0x3F & (c >>> 6))));
440         byteBuffer.put((byte) (0x80 | (0x3F & c)));
441       } else {
442         final char low;
443         if (i + 1 == sequence.length()
444                 || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
445           throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
446         }
447         int codePoint = Character.toCodePoint(c, low);
448         byteBuffer.put((byte) ((0xF << 4) | (codePoint >>> 18)));
449         byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 12))));
450         byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 6))));
451         byteBuffer.put((byte) (0x80 | (0x3F & codePoint)));
452       }
453     }
454   }
455 
encode(CharSequence sequence, byte[] bytes, int offset, int length)456   private static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
457     int utf16Length = sequence.length();
458     int j = offset;
459     int i = 0;
460     int limit = offset + length;
461     // Designed to take advantage of
462     // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
463     for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
464       bytes[j + i] = (byte) c;
465     }
466     if (i == utf16Length) {
467       return j + utf16Length;
468     }
469     j += i;
470     for (char c; i < utf16Length; i++) {
471       c = sequence.charAt(i);
472       if (c < 0x80 && j < limit) {
473         bytes[j++] = (byte) c;
474       } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
475         bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
476         bytes[j++] = (byte) (0x80 | (0x3F & c));
477       } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
478         // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
479         bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
480         bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
481         bytes[j++] = (byte) (0x80 | (0x3F & c));
482       } else if (j <= limit - 4) {
483         // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
484         final char low;
485         if (i + 1 == sequence.length()
486                 || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
487           throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
488         }
489         int codePoint = Character.toCodePoint(c, low);
490         bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
491         bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
492         bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
493         bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
494       } else {
495         throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
496       }
497     }
498     return j;
499   }
500 
501   // End guava UTF-8 methods
502 
503 
504   /** Write a {@code group} field to the stream. */
writeGroupNoTag(final MessageNano value)505   public void writeGroupNoTag(final MessageNano value) throws IOException {
506     value.writeTo(this);
507   }
508 
509   /** Write an embedded message field to the stream. */
writeMessageNoTag(final MessageNano value)510   public void writeMessageNoTag(final MessageNano value) throws IOException {
511     writeRawVarint32(value.getCachedSize());
512     value.writeTo(this);
513   }
514 
515   /** Write a {@code bytes} field to the stream. */
writeBytesNoTag(final byte[] value)516   public void writeBytesNoTag(final byte[] value) throws IOException {
517     writeRawVarint32(value.length);
518     writeRawBytes(value);
519   }
520 
521   /** Write a {@code uint32} field to the stream. */
writeUInt32NoTag(final int value)522   public void writeUInt32NoTag(final int value) throws IOException {
523     writeRawVarint32(value);
524   }
525 
526   /**
527    * Write an enum field to the stream.  Caller is responsible
528    * for converting the enum value to its numeric value.
529    */
writeEnumNoTag(final int value)530   public void writeEnumNoTag(final int value) throws IOException {
531     writeRawVarint32(value);
532   }
533 
534   /** Write an {@code sfixed32} field to the stream. */
writeSFixed32NoTag(final int value)535   public void writeSFixed32NoTag(final int value) throws IOException {
536     writeRawLittleEndian32(value);
537   }
538 
539   /** Write an {@code sfixed64} field to the stream. */
writeSFixed64NoTag(final long value)540   public void writeSFixed64NoTag(final long value) throws IOException {
541     writeRawLittleEndian64(value);
542   }
543 
544   /** Write an {@code sint32} field to the stream. */
writeSInt32NoTag(final int value)545   public void writeSInt32NoTag(final int value) throws IOException {
546     writeRawVarint32(encodeZigZag32(value));
547   }
548 
549   /** Write an {@code sint64} field to the stream. */
writeSInt64NoTag(final long value)550   public void writeSInt64NoTag(final long value) throws IOException {
551     writeRawVarint64(encodeZigZag64(value));
552   }
553 
554   // =================================================================
555 
556   /**
557    * Compute the number of bytes that would be needed to encode a
558    * {@code double} field, including tag.
559    */
computeDoubleSize(final int fieldNumber, final double value)560   public static int computeDoubleSize(final int fieldNumber,
561                                       final double value) {
562     return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
563   }
564 
565   /**
566    * Compute the number of bytes that would be needed to encode a
567    * {@code float} field, including tag.
568    */
computeFloatSize(final int fieldNumber, final float value)569   public static int computeFloatSize(final int fieldNumber, final float value) {
570     return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
571   }
572 
573   /**
574    * Compute the number of bytes that would be needed to encode a
575    * {@code uint64} field, including tag.
576    */
computeUInt64Size(final int fieldNumber, final long value)577   public static int computeUInt64Size(final int fieldNumber, final long value) {
578     return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
579   }
580 
581   /**
582    * Compute the number of bytes that would be needed to encode an
583    * {@code int64} field, including tag.
584    */
computeInt64Size(final int fieldNumber, final long value)585   public static int computeInt64Size(final int fieldNumber, final long value) {
586     return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
587   }
588 
589   /**
590    * Compute the number of bytes that would be needed to encode an
591    * {@code int32} field, including tag.
592    */
computeInt32Size(final int fieldNumber, final int value)593   public static int computeInt32Size(final int fieldNumber, final int value) {
594     return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
595   }
596 
597   /**
598    * Compute the number of bytes that would be needed to encode a
599    * {@code fixed64} field, including tag.
600    */
computeFixed64Size(final int fieldNumber, final long value)601   public static int computeFixed64Size(final int fieldNumber,
602                                        final long value) {
603     return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
604   }
605 
606   /**
607    * Compute the number of bytes that would be needed to encode a
608    * {@code fixed32} field, including tag.
609    */
computeFixed32Size(final int fieldNumber, final int value)610   public static int computeFixed32Size(final int fieldNumber,
611                                        final int value) {
612     return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
613   }
614 
615   /**
616    * Compute the number of bytes that would be needed to encode a
617    * {@code bool} field, including tag.
618    */
computeBoolSize(final int fieldNumber, final boolean value)619   public static int computeBoolSize(final int fieldNumber,
620                                     final boolean value) {
621     return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
622   }
623 
624   /**
625    * Compute the number of bytes that would be needed to encode a
626    * {@code string} field, including tag.
627    */
computeStringSize(final int fieldNumber, final String value)628   public static int computeStringSize(final int fieldNumber,
629                                       final String value) {
630     return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
631   }
632 
633   /**
634    * Compute the number of bytes that would be needed to encode a
635    * {@code group} field, including tag.
636    */
computeGroupSize(final int fieldNumber, final MessageNano value)637   public static int computeGroupSize(final int fieldNumber,
638                                      final MessageNano value) {
639     return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
640   }
641 
642   /**
643    * Compute the number of bytes that would be needed to encode an
644    * embedded message field, including tag.
645    */
computeMessageSize(final int fieldNumber, final MessageNano value)646   public static int computeMessageSize(final int fieldNumber,
647                                        final MessageNano value) {
648     return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
649   }
650 
651   /**
652    * Compute the number of bytes that would be needed to encode a
653    * {@code bytes} field, including tag.
654    */
computeBytesSize(final int fieldNumber, final byte[] value)655   public static int computeBytesSize(final int fieldNumber,
656                                      final byte[] value) {
657     return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
658   }
659 
660   /**
661    * Compute the number of bytes that would be needed to encode a
662    * {@code uint32} field, including tag.
663    */
computeUInt32Size(final int fieldNumber, final int value)664   public static int computeUInt32Size(final int fieldNumber, final int value) {
665     return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
666   }
667 
668   /**
669    * Compute the number of bytes that would be needed to encode an
670    * enum field, including tag.  Caller is responsible for converting the
671    * enum value to its numeric value.
672    */
computeEnumSize(final int fieldNumber, final int value)673   public static int computeEnumSize(final int fieldNumber, final int value) {
674     return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
675   }
676 
677   /**
678    * Compute the number of bytes that would be needed to encode an
679    * {@code sfixed32} field, including tag.
680    */
computeSFixed32Size(final int fieldNumber, final int value)681   public static int computeSFixed32Size(final int fieldNumber,
682                                         final int value) {
683     return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
684   }
685 
686   /**
687    * Compute the number of bytes that would be needed to encode an
688    * {@code sfixed64} field, including tag.
689    */
computeSFixed64Size(final int fieldNumber, final long value)690   public static int computeSFixed64Size(final int fieldNumber,
691                                         final long value) {
692     return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
693   }
694 
695   /**
696    * Compute the number of bytes that would be needed to encode an
697    * {@code sint32} field, including tag.
698    */
computeSInt32Size(final int fieldNumber, final int value)699   public static int computeSInt32Size(final int fieldNumber, final int value) {
700     return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
701   }
702 
703   /**
704    * Compute the number of bytes that would be needed to encode an
705    * {@code sint64} field, including tag.
706    */
computeSInt64Size(final int fieldNumber, final long value)707   public static int computeSInt64Size(final int fieldNumber, final long value) {
708     return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
709   }
710 
711   /**
712    * Compute the number of bytes that would be needed to encode a
713    * MessageSet extension to the stream.  For historical reasons,
714    * the wire format differs from normal fields.
715    */
716 //  public static int computeMessageSetExtensionSize(
717 //      final int fieldNumber, final MessageMicro value) {
718 //    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
719 //           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
720 //           computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
721 //  }
722 
723   /**
724    * Compute the number of bytes that would be needed to encode an
725    * unparsed MessageSet extension field to the stream.  For
726    * historical reasons, the wire format differs from normal fields.
727    */
728 //  public static int computeRawMessageSetExtensionSize(
729 //      final int fieldNumber, final ByteStringMicro value) {
730 //    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
731 //           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
732 //           computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
733 //  }
734 
735   // -----------------------------------------------------------------
736 
737   /**
738    * Compute the number of bytes that would be needed to encode a
739    * {@code double} field, including tag.
740    */
computeDoubleSizeNoTag(final double value)741   public static int computeDoubleSizeNoTag(final double value) {
742     return LITTLE_ENDIAN_64_SIZE;
743   }
744 
745   /**
746    * Compute the number of bytes that would be needed to encode a
747    * {@code float} field, including tag.
748    */
computeFloatSizeNoTag(final float value)749   public static int computeFloatSizeNoTag(final float value) {
750     return LITTLE_ENDIAN_32_SIZE;
751   }
752 
753   /**
754    * Compute the number of bytes that would be needed to encode a
755    * {@code uint64} field, including tag.
756    */
computeUInt64SizeNoTag(final long value)757   public static int computeUInt64SizeNoTag(final long value) {
758     return computeRawVarint64Size(value);
759   }
760 
761   /**
762    * Compute the number of bytes that would be needed to encode an
763    * {@code int64} field, including tag.
764    */
computeInt64SizeNoTag(final long value)765   public static int computeInt64SizeNoTag(final long value) {
766     return computeRawVarint64Size(value);
767   }
768 
769   /**
770    * Compute the number of bytes that would be needed to encode an
771    * {@code int32} field, including tag.
772    */
computeInt32SizeNoTag(final int value)773   public static int computeInt32SizeNoTag(final int value) {
774     if (value >= 0) {
775       return computeRawVarint32Size(value);
776     } else {
777       // Must sign-extend.
778       return 10;
779     }
780   }
781 
782   /**
783    * Compute the number of bytes that would be needed to encode a
784    * {@code fixed64} field.
785    */
computeFixed64SizeNoTag(final long value)786   public static int computeFixed64SizeNoTag(final long value) {
787     return LITTLE_ENDIAN_64_SIZE;
788   }
789 
790   /**
791    * Compute the number of bytes that would be needed to encode a
792    * {@code fixed32} field.
793    */
computeFixed32SizeNoTag(final int value)794   public static int computeFixed32SizeNoTag(final int value) {
795     return LITTLE_ENDIAN_32_SIZE;
796   }
797 
798   /**
799    * Compute the number of bytes that would be needed to encode a
800    * {@code bool} field.
801    */
computeBoolSizeNoTag(final boolean value)802   public static int computeBoolSizeNoTag(final boolean value) {
803     return 1;
804   }
805 
806   /**
807    * Compute the number of bytes that would be needed to encode a
808    * {@code string} field.
809    */
computeStringSizeNoTag(final String value)810   public static int computeStringSizeNoTag(final String value) {
811     final int length = encodedLength(value);
812     return computeRawVarint32Size(length) + length;
813   }
814 
815   /**
816    * Compute the number of bytes that would be needed to encode a
817    * {@code group} field.
818    */
computeGroupSizeNoTag(final MessageNano value)819   public static int computeGroupSizeNoTag(final MessageNano value) {
820     return value.getSerializedSize();
821   }
822 
823   /**
824    * Compute the number of bytes that would be needed to encode an embedded
825    * message field.
826    */
computeMessageSizeNoTag(final MessageNano value)827   public static int computeMessageSizeNoTag(final MessageNano value) {
828     final int size = value.getSerializedSize();
829     return computeRawVarint32Size(size) + size;
830   }
831 
832   /**
833    * Compute the number of bytes that would be needed to encode a
834    * {@code bytes} field.
835    */
computeBytesSizeNoTag(final byte[] value)836   public static int computeBytesSizeNoTag(final byte[] value) {
837     return computeRawVarint32Size(value.length) + value.length;
838   }
839 
840   /**
841    * Compute the number of bytes that would be needed to encode a
842    * {@code uint32} field.
843    */
computeUInt32SizeNoTag(final int value)844   public static int computeUInt32SizeNoTag(final int value) {
845     return computeRawVarint32Size(value);
846   }
847 
848   /**
849    * Compute the number of bytes that would be needed to encode an enum field.
850    * Caller is responsible for converting the enum value to its numeric value.
851    */
computeEnumSizeNoTag(final int value)852   public static int computeEnumSizeNoTag(final int value) {
853     return computeRawVarint32Size(value);
854   }
855 
856   /**
857    * Compute the number of bytes that would be needed to encode an
858    * {@code sfixed32} field.
859    */
computeSFixed32SizeNoTag(final int value)860   public static int computeSFixed32SizeNoTag(final int value) {
861     return LITTLE_ENDIAN_32_SIZE;
862   }
863 
864   /**
865    * Compute the number of bytes that would be needed to encode an
866    * {@code sfixed64} field.
867    */
computeSFixed64SizeNoTag(final long value)868   public static int computeSFixed64SizeNoTag(final long value) {
869     return LITTLE_ENDIAN_64_SIZE;
870   }
871 
872   /**
873    * Compute the number of bytes that would be needed to encode an
874    * {@code sint32} field.
875    */
computeSInt32SizeNoTag(final int value)876   public static int computeSInt32SizeNoTag(final int value) {
877     return computeRawVarint32Size(encodeZigZag32(value));
878   }
879 
880   /**
881    * Compute the number of bytes that would be needed to encode an
882    * {@code sint64} field.
883    */
computeSInt64SizeNoTag(final long value)884   public static int computeSInt64SizeNoTag(final long value) {
885     return computeRawVarint64Size(encodeZigZag64(value));
886   }
887 
888   // =================================================================
889 
890   /**
891    * If writing to a flat array, return the space left in the array.
892    * Otherwise, throws {@code UnsupportedOperationException}.
893    */
spaceLeft()894   public int spaceLeft() {
895     return buffer.remaining();
896   }
897 
898   /**
899    * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
900    * a byte array that is exactly big enough to hold a message, then write to
901    * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
902    * after writing verifies that the message was actually as big as expected,
903    * which can help catch bugs.
904    */
checkNoSpaceLeft()905   public void checkNoSpaceLeft() {
906     if (spaceLeft() != 0) {
907       throw new IllegalStateException(
908         "Did not write as much data as expected.");
909     }
910   }
911 
912   /**
913    * Returns the position within the internal buffer.
914    */
position()915   public int position() {
916     return buffer.position();
917   }
918 
919   /**
920    * Resets the position within the internal buffer to zero.
921    *
922    * @see #position
923    * @see #spaceLeft
924    */
reset()925   public void reset() {
926     buffer.clear();
927   }
928 
929   /**
930    * If you create a CodedOutputStream around a simple flat array, you must
931    * not attempt to write more bytes than the array has space.  Otherwise,
932    * this exception will be thrown.
933    */
934   public static class OutOfSpaceException extends IOException {
935     private static final long serialVersionUID = -6947486886997889499L;
936 
OutOfSpaceException(int position, int limit)937     OutOfSpaceException(int position, int limit) {
938       super("CodedOutputStream was writing to a flat byte array and ran " +
939             "out of space (pos " + position + " limit " + limit + ").");
940     }
941   }
942 
943   /** Write a single byte. */
writeRawByte(final byte value)944   public void writeRawByte(final byte value) throws IOException {
945     if (!buffer.hasRemaining()) {
946       // We're writing to a single buffer.
947       throw new OutOfSpaceException(buffer.position(), buffer.limit());
948     }
949 
950     buffer.put(value);
951   }
952 
953   /** Write a single byte, represented by an integer value. */
writeRawByte(final int value)954   public void writeRawByte(final int value) throws IOException {
955     writeRawByte((byte) value);
956   }
957 
958   /** Write an array of bytes. */
writeRawBytes(final byte[] value)959   public void writeRawBytes(final byte[] value) throws IOException {
960     writeRawBytes(value, 0, value.length);
961   }
962 
963   /** Write part of an array of bytes. */
writeRawBytes(final byte[] value, int offset, int length)964   public void writeRawBytes(final byte[] value, int offset, int length)
965                             throws IOException {
966     if (buffer.remaining() >= length) {
967       buffer.put(value, offset, length);
968     } else {
969       // We're writing to a single buffer.
970       throw new OutOfSpaceException(buffer.position(), buffer.limit());
971     }
972   }
973 
974   /** Encode and write a tag. */
writeTag(final int fieldNumber, final int wireType)975   public void writeTag(final int fieldNumber, final int wireType)
976                        throws IOException {
977     writeRawVarint32(WireFormatNano.makeTag(fieldNumber, wireType));
978   }
979 
980   /** Compute the number of bytes that would be needed to encode a tag. */
computeTagSize(final int fieldNumber)981   public static int computeTagSize(final int fieldNumber) {
982     return computeRawVarint32Size(WireFormatNano.makeTag(fieldNumber, 0));
983   }
984 
985   /**
986    * Encode and write a varint.  {@code value} is treated as
987    * unsigned, so it won't be sign-extended if negative.
988    */
writeRawVarint32(int value)989   public void writeRawVarint32(int value) throws IOException {
990     while (true) {
991       if ((value & ~0x7F) == 0) {
992         writeRawByte(value);
993         return;
994       } else {
995         writeRawByte((value & 0x7F) | 0x80);
996         value >>>= 7;
997       }
998     }
999   }
1000 
1001   /**
1002    * Compute the number of bytes that would be needed to encode a varint.
1003    * {@code value} is treated as unsigned, so it won't be sign-extended if
1004    * negative.
1005    */
computeRawVarint32Size(final int value)1006   public static int computeRawVarint32Size(final int value) {
1007     if ((value & (0xffffffff <<  7)) == 0) return 1;
1008     if ((value & (0xffffffff << 14)) == 0) return 2;
1009     if ((value & (0xffffffff << 21)) == 0) return 3;
1010     if ((value & (0xffffffff << 28)) == 0) return 4;
1011     return 5;
1012   }
1013 
1014   /** Encode and write a varint. */
writeRawVarint64(long value)1015   public void writeRawVarint64(long value) throws IOException {
1016     while (true) {
1017       if ((value & ~0x7FL) == 0) {
1018         writeRawByte((int)value);
1019         return;
1020       } else {
1021         writeRawByte(((int)value & 0x7F) | 0x80);
1022         value >>>= 7;
1023       }
1024     }
1025   }
1026 
1027   /** Compute the number of bytes that would be needed to encode a varint. */
computeRawVarint64Size(final long value)1028   public static int computeRawVarint64Size(final long value) {
1029     if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
1030     if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
1031     if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
1032     if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
1033     if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
1034     if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
1035     if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
1036     if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
1037     if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
1038     return 10;
1039   }
1040 
1041   /** Write a little-endian 32-bit integer. */
writeRawLittleEndian32(final int value)1042   public void writeRawLittleEndian32(final int value) throws IOException {
1043     if (buffer.remaining() < 4) {
1044       throw new OutOfSpaceException(buffer.position(), buffer.limit());
1045     }
1046     buffer.putInt(value);
1047   }
1048 
1049   public static final int LITTLE_ENDIAN_32_SIZE = 4;
1050 
1051   /** Write a little-endian 64-bit integer. */
writeRawLittleEndian64(final long value)1052   public void writeRawLittleEndian64(final long value) throws IOException {
1053     if (buffer.remaining() < 8) {
1054       throw new OutOfSpaceException(buffer.position(), buffer.limit());
1055     }
1056     buffer.putLong(value);
1057   }
1058 
1059   public static final int LITTLE_ENDIAN_64_SIZE = 8;
1060 
1061   /**
1062    * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
1063    * into values that can be efficiently encoded with varint.  (Otherwise,
1064    * negative values must be sign-extended to 64 bits to be varint encoded,
1065    * thus always taking 10 bytes on the wire.)
1066    *
1067    * @param n A signed 32-bit integer.
1068    * @return An unsigned 32-bit integer, stored in a signed int because
1069    *         Java has no explicit unsigned support.
1070    */
encodeZigZag32(final int n)1071   public static int encodeZigZag32(final int n) {
1072     // Note:  the right-shift must be arithmetic
1073     return (n << 1) ^ (n >> 31);
1074   }
1075 
1076   /**
1077    * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
1078    * into values that can be efficiently encoded with varint.  (Otherwise,
1079    * negative values must be sign-extended to 64 bits to be varint encoded,
1080    * thus always taking 10 bytes on the wire.)
1081    *
1082    * @param n A signed 64-bit integer.
1083    * @return An unsigned 64-bit integer, stored in a signed int because
1084    *         Java has no explicit unsigned support.
1085    */
encodeZigZag64(final long n)1086   public static long encodeZigZag64(final long n) {
1087     // Note:  the right-shift must be arithmetic
1088     return (n << 1) ^ (n >> 63);
1089   }
1090 
computeFieldSize(int number, int type, Object object)1091   static int computeFieldSize(int number, int type, Object object) {
1092     switch (type) {
1093       case InternalNano.TYPE_BOOL:
1094         return computeBoolSize(number, (Boolean) object);
1095       case InternalNano.TYPE_BYTES:
1096         return computeBytesSize(number, (byte[]) object);
1097       case InternalNano.TYPE_STRING:
1098         return computeStringSize(number, (String) object);
1099       case InternalNano.TYPE_FLOAT:
1100         return computeFloatSize(number, (Float) object);
1101       case InternalNano.TYPE_DOUBLE:
1102         return computeDoubleSize(number, (Double) object);
1103       case InternalNano.TYPE_ENUM:
1104         return computeEnumSize(number, (Integer) object);
1105       case InternalNano.TYPE_FIXED32:
1106         return computeFixed32Size(number, (Integer) object);
1107       case InternalNano.TYPE_INT32:
1108         return computeInt32Size(number, (Integer) object);
1109       case InternalNano.TYPE_UINT32:
1110         return computeUInt32Size(number, (Integer) object);
1111       case InternalNano.TYPE_SINT32:
1112         return computeSInt32Size(number, (Integer) object);
1113       case InternalNano.TYPE_SFIXED32:
1114         return computeSFixed32Size(number, (Integer) object);
1115       case InternalNano.TYPE_INT64:
1116         return computeInt64Size(number, (Long) object);
1117       case InternalNano.TYPE_UINT64:
1118         return computeUInt64Size(number, (Long) object);
1119       case InternalNano.TYPE_SINT64:
1120         return computeSInt64Size(number, (Long) object);
1121       case InternalNano.TYPE_FIXED64:
1122         return computeFixed64Size(number, (Long) object);
1123       case InternalNano.TYPE_SFIXED64:
1124         return computeSFixed64Size(number, (Long) object);
1125       case InternalNano.TYPE_MESSAGE:
1126         return computeMessageSize(number, (MessageNano) object);
1127       case InternalNano.TYPE_GROUP:
1128         return computeGroupSize(number, (MessageNano) object);
1129       default:
1130         throw new IllegalArgumentException("Unknown type: " + type);
1131     }
1132   }
1133 
writeField(int number, int type, Object value)1134   void writeField(int number, int type, Object value)
1135       throws IOException {
1136     switch (type) {
1137       case InternalNano.TYPE_DOUBLE:
1138         Double doubleValue = (Double) value;
1139         writeDouble(number, doubleValue);
1140         break;
1141       case InternalNano.TYPE_FLOAT:
1142         Float floatValue = (Float) value;
1143         writeFloat(number, floatValue);
1144         break;
1145       case InternalNano.TYPE_INT64:
1146         Long int64Value = (Long) value;
1147         writeInt64(number, int64Value);
1148         break;
1149       case InternalNano.TYPE_UINT64:
1150         Long uint64Value = (Long) value;
1151         writeUInt64(number, uint64Value);
1152         break;
1153       case InternalNano.TYPE_INT32:
1154         Integer int32Value = (Integer) value;
1155         writeInt32(number, int32Value);
1156         break;
1157       case InternalNano.TYPE_FIXED64:
1158         Long fixed64Value = (Long) value;
1159         writeFixed64(number, fixed64Value);
1160         break;
1161       case InternalNano.TYPE_FIXED32:
1162         Integer fixed32Value = (Integer) value;
1163         writeFixed32(number, fixed32Value);
1164         break;
1165       case InternalNano.TYPE_BOOL:
1166         Boolean boolValue = (Boolean) value;
1167         writeBool(number, boolValue);
1168         break;
1169       case InternalNano.TYPE_STRING:
1170         String stringValue = (String) value;
1171         writeString(number, stringValue);
1172         break;
1173       case InternalNano.TYPE_BYTES:
1174         byte[] bytesValue = (byte[]) value;
1175         writeBytes(number, bytesValue);
1176         break;
1177       case InternalNano.TYPE_UINT32:
1178         Integer uint32Value = (Integer) value;
1179         writeUInt32(number, uint32Value);
1180         break;
1181       case InternalNano.TYPE_ENUM:
1182         Integer enumValue = (Integer) value;
1183         writeEnum(number, enumValue);
1184         break;
1185       case InternalNano.TYPE_SFIXED32:
1186         Integer sfixed32Value = (Integer) value;
1187         writeSFixed32(number, sfixed32Value);
1188         break;
1189       case InternalNano.TYPE_SFIXED64:
1190         Long sfixed64Value = (Long) value;
1191         writeSFixed64(number, sfixed64Value);
1192         break;
1193       case InternalNano.TYPE_SINT32:
1194         Integer sint32Value = (Integer) value;
1195         writeSInt32(number, sint32Value);
1196         break;
1197       case InternalNano.TYPE_SINT64:
1198         Long sint64Value = (Long) value;
1199         writeSInt64(number, sint64Value);
1200         break;
1201       case InternalNano.TYPE_MESSAGE:
1202         MessageNano messageValue = (MessageNano) value;
1203         writeMessage(number, messageValue);
1204         break;
1205       case InternalNano.TYPE_GROUP:
1206         MessageNano groupValue = (MessageNano) value;
1207         writeGroup(number, groupValue);
1208         break;
1209       default:
1210         throw new IOException("Unknown type: " + type);
1211     }
1212   }
1213 
1214 }
1215