1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util.proto;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.util.Log;
22 
23 import java.io.FileDescriptor;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.UnsupportedEncodingException;
28 
29 /**
30  * Class to write to a protobuf stream.
31  *
32  * <p>
33  * This API is not as convenient or type safe as the standard protobuf
34  * classes. If possible, the best recommended library is to use protobuf lite.
35  * However, in environments (such as the Android platform itself), a
36  * more memory efficient version is necessary.
37  *
38  * <p>Each write method takes an ID code from the protoc generated classes
39  * and the value to write.  To make a nested object, call {@link #start(long)}
40  * and then {@link #end(long)} when you are done.
41  *
42  * <p>The ID codes have type information embedded into them, so if you call
43  * the incorrect function you will get an {@link IllegalArgumentException}.
44  *
45  * <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}.
46  *
47  * stream as the top-level objects are finished.
48  *
49  */
50 
51 /* IMPLEMENTATION NOTES
52  *
53  * Because protobuf has inner values, and they are length prefixed, and
54  * those sizes themselves are stored with a variable length encoding, it
55  * is impossible to know how big an object will be in a single pass.
56  *
57  * The traditional way is to copy the in-memory representation of an object
58  * into the generated proto Message objects, do a traversal of those to
59  * cache the size, and then write the size-prefixed buffers.
60  *
61  * We are trying to avoid too much generated code here, but this class still
62  * needs to have API.  We can't have the multiple passes be done by the
63  * calling code.  In addition, we want to avoid the memory high water mark
64  * of duplicating all of the values into the traditional in-memory Message
65  * objects. We need to find another way.
66  *
67  * So what we do here is to let the calling code write the data into a
68  * byte[] (actually a collection of them wrapped in the EncodedBuffer class),
69  * but not do the varint encoding of the sub-message sizes.  Then, we do a
70  * recursive traversal of the buffer itself, calculating the sizes (which are
71  * then knowable, although still not the actual sizes in the buffer because of
72  * possible further nesting).  Then we do a third pass, compacting the
73  * buffer and varint encoding the sizes.
74  *
75  * This gets us a relatively small number of fixed-size allocations,
76  * which is less likely to cause memory fragmentation or churn the GC, and
77  * the same number of data copies as we would have gotten with setting it
78  * field-by-field in generated code, and no code bloat from generated code.
79  * The final data copy is also done with System.arraycopy, which will be
80  * more efficient, in general, than doing the individual fields twice (as in
81  * the traditional way).
82  *
83  * To accomplish the multiple passes, whenever we write a
84  * WIRE_TYPE_LENGTH_DELIMITED field, we write the size occupied in our
85  * buffer as a fixed 32 bit int (called childRawSize), not a variable length
86  * one. We reserve another 32 bit slot for the computed size (called
87  * childEncodedSize).  If we know the size up front, as we do for strings
88  * and byte[], then we also put that into childEncodedSize, if we don't, we
89  * write the negative of childRawSize, as a sentinel that we need to
90  * compute it during the second pass and recursively compact it during the
91  * third pass.
92  *
93  * Unsigned size varints can be up to five bytes long, but we reserve eight
94  * bytes for overhead, so we know that when we compact the buffer, there
95  * will always be space for the encoded varint.
96  *
97  * When we can figure out the size ahead of time, we do, in order
98  * to save overhead with recalculating it, and with the later arraycopy.
99  *
100  * During the period between when the caller has called #start, but
101  * not yet called #end, we maintain a linked list of the tokens
102  * returned by #start, stored in those 8 bytes of size storage space.
103  * We use that linked list of tokens to ensure that the caller has
104  * correctly matched pairs of #start and #end calls, and issue
105  * errors if they are not matched.
106  */
107 @android.ravenwood.annotation.RavenwoodKeepWholeClass
108 public final class ProtoOutputStream extends ProtoStream {
109     /**
110      * @hide
111      */
112     public static final String TAG = "ProtoOutputStream";
113 
114     /**
115      * Our buffer.
116      */
117     private EncodedBuffer mBuffer;
118 
119     /**
120      * Our stream.  If there is one.
121      */
122     private OutputStream mStream;
123 
124     /**
125      * Current nesting depth of startObject calls.
126      */
127     private int mDepth;
128 
129     /**
130      * An ID given to objects and returned in the token from startObject
131      * and stored in the buffer until endObject is called, where the two
132      * are checked.
133      *
134      * <p>Starts at -1 and becomes more negative, so the values
135      * aren't likely to alias with the size it will be overwritten with,
136      * which tend to be small, and we will be more likely to catch when
137      * the caller of endObject uses a stale token that they didn't intend
138      * to (e.g. copy and paste error).
139      */
140     private int mNextObjectId = -1;
141 
142     /**
143      * The object token we are expecting in endObject.
144      *
145      * <p>If another call to startObject happens, this is written to that location, which gives
146      * us a stack, stored in the space for the as-yet unused size fields.
147      */
148     private long mExpectedObjectToken;
149 
150     /**
151      * Index in mBuffer that we should start copying from on the next
152      * pass of compaction.
153      */
154     private int mCopyBegin;
155 
156     /**
157      * Whether we've already compacted
158      */
159     private boolean mCompacted;
160 
161     /**
162      * Construct a {@link ProtoOutputStream} with the default chunk size.
163      *
164      * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
165      */
ProtoOutputStream()166     public ProtoOutputStream() {
167         this(0);
168     }
169 
170     /**
171      * Construct a {@link ProtoOutputStream with the given chunk size.
172      *
173      * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
174      */
ProtoOutputStream(int chunkSize)175     public ProtoOutputStream(int chunkSize) {
176         mBuffer = new EncodedBuffer(chunkSize);
177     }
178 
179     /**
180      * Construct a {@link ProtoOutputStream} that sits on top of an {@link OutputStream}.
181      *
182      * <p>The {@link #flush()} method must be called when done writing
183      * to flush any remaining data, although data *may* be written at intermediate
184      * points within the writing as well.
185      */
ProtoOutputStream(@onNull OutputStream stream)186     public ProtoOutputStream(@NonNull OutputStream stream) {
187         this();
188         mStream = stream;
189     }
190 
191     /**
192      * Construct a {@link ProtoOutputStream} that sits on top of a {@link FileDescriptor}.
193      *
194      * <p>The {@link #flush()} method must be called when done writing
195      * to flush any remaining data, although data *may* be written at intermediate
196      * points within the writing as well.
197      *
198      * @hide
199      */
ProtoOutputStream(@onNull FileDescriptor fd)200     public ProtoOutputStream(@NonNull FileDescriptor fd) {
201         this(new FileOutputStream(fd));
202     }
203 
204     /**
205      * Returns the total size of the data that has been written, after full
206      * protobuf encoding has occurred.
207      *
208      * @return the uncompressed buffer size
209      */
getRawSize()210     public int getRawSize() {
211         if (mCompacted) {
212             return getBytes().length;
213         } else {
214             return mBuffer.getSize();
215         }
216     }
217 
218     /**
219      * Write a value for the given fieldId.
220      *
221      * <p>Will automatically convert for the following field types, and
222      * throw an exception for others: double, float, int32, int64, uint32, uint64,
223      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
224      *
225      * @param fieldId The field identifier constant from the generated class.
226      * @param val The value.
227      */
write(long fieldId, double val)228     public void write(long fieldId, double val) {
229         assertNotCompacted();
230         final int id = (int)fieldId;
231 
232         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
233             // double
234             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
235                 writeDoubleImpl(id, (double)val);
236                 break;
237             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
238             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
239                 writeRepeatedDoubleImpl(id, (double)val);
240                 break;
241             // float
242             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
243                 writeFloatImpl(id, (float)val);
244                 break;
245             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
246             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
247                 writeRepeatedFloatImpl(id, (float)val);
248                 break;
249             // int32
250             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
251                 writeInt32Impl(id, (int)val);
252                 break;
253             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
254             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
255                 writeRepeatedInt32Impl(id, (int)val);
256                 break;
257             // int64
258             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
259                 writeInt64Impl(id, (long)val);
260                 break;
261             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
262             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
263                 writeRepeatedInt64Impl(id, (long)val);
264                 break;
265             // uint32
266             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
267                 writeUInt32Impl(id, (int)val);
268                 break;
269             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
270             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
271                 writeRepeatedUInt32Impl(id, (int)val);
272                 break;
273             // uint64
274             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
275                 writeUInt64Impl(id, (long)val);
276                 break;
277             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
278             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
279                 writeRepeatedUInt64Impl(id, (long)val);
280                 break;
281             // sint32
282             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
283                 writeSInt32Impl(id, (int)val);
284                 break;
285             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
286             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
287                 writeRepeatedSInt32Impl(id, (int)val);
288                 break;
289             // sint64
290             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
291                 writeSInt64Impl(id, (long)val);
292                 break;
293             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
294             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
295                 writeRepeatedSInt64Impl(id, (long)val);
296                 break;
297             // fixed32
298             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
299                 writeFixed32Impl(id, (int)val);
300                 break;
301             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
302             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
303                 writeRepeatedFixed32Impl(id, (int)val);
304                 break;
305             // fixed64
306             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
307                 writeFixed64Impl(id, (long)val);
308                 break;
309             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
310             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
311                 writeRepeatedFixed64Impl(id, (long)val);
312                 break;
313             // sfixed32
314             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
315                 writeSFixed32Impl(id, (int)val);
316                 break;
317             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
318             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
319                 writeRepeatedSFixed32Impl(id, (int)val);
320                 break;
321             // sfixed64
322             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
323                 writeSFixed64Impl(id, (long)val);
324                 break;
325             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
326             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
327                 writeRepeatedSFixed64Impl(id, (long)val);
328                 break;
329             // bool
330             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
331                 writeBoolImpl(id, val != 0);
332                 break;
333             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
334             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
335                 writeRepeatedBoolImpl(id, val != 0);
336                 break;
337             // enum
338             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
339                 writeEnumImpl(id, (int)val);
340                 break;
341             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
342             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
343                 writeRepeatedEnumImpl(id, (int)val);
344                 break;
345             // string, bytes, object not allowed here.
346             default: {
347                 throw new IllegalArgumentException("Attempt to call write(long, double) with "
348                         + getFieldIdString(fieldId));
349             }
350         }
351     }
352 
353     /**
354      * Write a value for the given fieldId.
355      *
356      * <p>Will automatically convert for the following field types, and
357      * throw an exception for others: double, float, int32, int64, uint32, uint64,
358      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
359      *
360      * @param fieldId The field identifier constant from the generated class.
361      * @param val The value.
362      */
write(long fieldId, float val)363     public void write(long fieldId, float val) {
364         assertNotCompacted();
365         final int id = (int)fieldId;
366 
367         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
368             // double
369             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
370                 writeDoubleImpl(id, (double)val);
371                 break;
372             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
373             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
374                 writeRepeatedDoubleImpl(id, (double)val);
375                 break;
376             // float
377             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
378                 writeFloatImpl(id, (float)val);
379                 break;
380             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
381             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
382                 writeRepeatedFloatImpl(id, (float)val);
383                 break;
384             // int32
385             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
386                 writeInt32Impl(id, (int)val);
387                 break;
388             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
389             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
390                 writeRepeatedInt32Impl(id, (int)val);
391                 break;
392             // int64
393             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
394                 writeInt64Impl(id, (long)val);
395                 break;
396             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
397             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
398                 writeRepeatedInt64Impl(id, (long)val);
399                 break;
400             // uint32
401             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
402                 writeUInt32Impl(id, (int)val);
403                 break;
404             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
405             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
406                 writeRepeatedUInt32Impl(id, (int)val);
407                 break;
408             // uint64
409             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
410                 writeUInt64Impl(id, (long)val);
411                 break;
412             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
413             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
414                 writeRepeatedUInt64Impl(id, (long)val);
415                 break;
416             // sint32
417             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
418                 writeSInt32Impl(id, (int)val);
419                 break;
420             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
421             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
422                 writeRepeatedSInt32Impl(id, (int)val);
423                 break;
424             // sint64
425             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
426                 writeSInt64Impl(id, (long)val);
427                 break;
428             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
429             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
430                 writeRepeatedSInt64Impl(id, (long)val);
431                 break;
432             // fixed32
433             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
434                 writeFixed32Impl(id, (int)val);
435                 break;
436             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
437             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
438                 writeRepeatedFixed32Impl(id, (int)val);
439                 break;
440             // fixed64
441             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
442                 writeFixed64Impl(id, (long)val);
443                 break;
444             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
445             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
446                 writeRepeatedFixed64Impl(id, (long)val);
447                 break;
448             // sfixed32
449             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
450                 writeSFixed32Impl(id, (int)val);
451                 break;
452             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
453             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
454                 writeRepeatedSFixed32Impl(id, (int)val);
455                 break;
456             // sfixed64
457             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
458                 writeSFixed64Impl(id, (long)val);
459                 break;
460             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
461             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
462                 writeRepeatedSFixed64Impl(id, (long)val);
463                 break;
464             // bool
465             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
466                 writeBoolImpl(id, val != 0);
467                 break;
468             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
469             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
470                 writeRepeatedBoolImpl(id, val != 0);
471                 break;
472             // enum
473             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
474                 writeEnumImpl(id, (int)val);
475                 break;
476             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
477             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
478                 writeRepeatedEnumImpl(id, (int)val);
479                 break;
480             // string, bytes, object not allowed here.
481             default: {
482                 throw new IllegalArgumentException("Attempt to call write(long, float) with "
483                         + getFieldIdString(fieldId));
484             }
485         }
486     }
487 
488     /**
489      * Write a value for the given fieldId.
490      *
491      * <p>Will automatically convert for the following field types, and
492      * throw an exception for others: double, float, int32, int64, uint32, uint64,
493      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
494      *
495      * @param fieldId The field identifier constant from the generated class.
496      * @param val The value.
497      */
write(long fieldId, int val)498     public void write(long fieldId, int val) {
499         assertNotCompacted();
500         final int id = (int)fieldId;
501 
502         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
503             // double
504             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
505                 writeDoubleImpl(id, (double)val);
506                 break;
507             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
508             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
509                 writeRepeatedDoubleImpl(id, (double)val);
510                 break;
511             // float
512             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
513                 writeFloatImpl(id, (float)val);
514                 break;
515             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
516             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
517                 writeRepeatedFloatImpl(id, (float)val);
518                 break;
519             // int32
520             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
521                 writeInt32Impl(id, (int)val);
522                 break;
523             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
524             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
525                 writeRepeatedInt32Impl(id, (int)val);
526                 break;
527             // int64
528             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
529                 writeInt64Impl(id, (long)val);
530                 break;
531             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
532             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
533                 writeRepeatedInt64Impl(id, (long)val);
534                 break;
535             // uint32
536             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
537                 writeUInt32Impl(id, (int)val);
538                 break;
539             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
540             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
541                 writeRepeatedUInt32Impl(id, (int)val);
542                 break;
543             // uint64
544             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
545                 writeUInt64Impl(id, (long)val);
546                 break;
547             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
548             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
549                 writeRepeatedUInt64Impl(id, (long)val);
550                 break;
551             // sint32
552             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
553                 writeSInt32Impl(id, (int)val);
554                 break;
555             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
556             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
557                 writeRepeatedSInt32Impl(id, (int)val);
558                 break;
559             // sint64
560             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
561                 writeSInt64Impl(id, (long)val);
562                 break;
563             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
564             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
565                 writeRepeatedSInt64Impl(id, (long)val);
566                 break;
567             // fixed32
568             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
569                 writeFixed32Impl(id, (int)val);
570                 break;
571             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
572             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
573                 writeRepeatedFixed32Impl(id, (int)val);
574                 break;
575             // fixed64
576             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
577                 writeFixed64Impl(id, (long)val);
578                 break;
579             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
580             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
581                 writeRepeatedFixed64Impl(id, (long)val);
582                 break;
583             // sfixed32
584             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
585                 writeSFixed32Impl(id, (int)val);
586                 break;
587             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
588             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
589                 writeRepeatedSFixed32Impl(id, (int)val);
590                 break;
591             // sfixed64
592             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
593                 writeSFixed64Impl(id, (long)val);
594                 break;
595             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
596             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
597                 writeRepeatedSFixed64Impl(id, (long)val);
598                 break;
599             // bool
600             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
601                 writeBoolImpl(id, val != 0);
602                 break;
603             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
604             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
605                 writeRepeatedBoolImpl(id, val != 0);
606                 break;
607             // enum
608             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
609                 writeEnumImpl(id, (int)val);
610                 break;
611             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
612             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
613                 writeRepeatedEnumImpl(id, (int)val);
614                 break;
615             // string, bytes, object not allowed here.
616             default: {
617                 throw new IllegalArgumentException("Attempt to call write(long, int) with "
618                         + getFieldIdString(fieldId));
619             }
620         }
621     }
622 
623     /**
624      * Write a value for the given fieldId.
625      *
626      * <p>Will automatically convert for the following field types, and
627      * throw an exception for others: double, float, int32, int64, uint32, uint64,
628      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
629      *
630      * @param fieldId The field identifier constant from the generated class.
631      * @param val The value.
632      */
write(long fieldId, long val)633     public void write(long fieldId, long val) {
634         assertNotCompacted();
635         final int id = (int)fieldId;
636 
637         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
638             // double
639             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
640                 writeDoubleImpl(id, (double)val);
641                 break;
642             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
643             case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
644                 writeRepeatedDoubleImpl(id, (double)val);
645                 break;
646             // float
647             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
648                 writeFloatImpl(id, (float)val);
649                 break;
650             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
651             case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
652                 writeRepeatedFloatImpl(id, (float)val);
653                 break;
654             // int32
655             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
656                 writeInt32Impl(id, (int)val);
657                 break;
658             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
659             case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
660                 writeRepeatedInt32Impl(id, (int)val);
661                 break;
662             // int64
663             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
664                 writeInt64Impl(id, (long)val);
665                 break;
666             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
667             case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
668                 writeRepeatedInt64Impl(id, (long)val);
669                 break;
670             // uint32
671             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
672                 writeUInt32Impl(id, (int)val);
673                 break;
674             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
675             case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
676                 writeRepeatedUInt32Impl(id, (int)val);
677                 break;
678             // uint64
679             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
680                 writeUInt64Impl(id, (long)val);
681                 break;
682             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
683             case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
684                 writeRepeatedUInt64Impl(id, (long)val);
685                 break;
686             // sint32
687             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
688                 writeSInt32Impl(id, (int)val);
689                 break;
690             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
691             case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
692                 writeRepeatedSInt32Impl(id, (int)val);
693                 break;
694             // sint64
695             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
696                 writeSInt64Impl(id, (long)val);
697                 break;
698             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
699             case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
700                 writeRepeatedSInt64Impl(id, (long)val);
701                 break;
702             // fixed32
703             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
704                 writeFixed32Impl(id, (int)val);
705                 break;
706             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
707             case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
708                 writeRepeatedFixed32Impl(id, (int)val);
709                 break;
710             // fixed64
711             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
712                 writeFixed64Impl(id, (long)val);
713                 break;
714             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
715             case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
716                 writeRepeatedFixed64Impl(id, (long)val);
717                 break;
718             // sfixed32
719             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
720                 writeSFixed32Impl(id, (int)val);
721                 break;
722             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
723             case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
724                 writeRepeatedSFixed32Impl(id, (int)val);
725                 break;
726             // sfixed64
727             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
728                 writeSFixed64Impl(id, (long)val);
729                 break;
730             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
731             case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
732                 writeRepeatedSFixed64Impl(id, (long)val);
733                 break;
734             // bool
735             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
736                 writeBoolImpl(id, val != 0);
737                 break;
738             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
739             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
740                 writeRepeatedBoolImpl(id, val != 0);
741                 break;
742             // enum
743             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
744                 writeEnumImpl(id, (int)val);
745                 break;
746             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
747             case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
748                 writeRepeatedEnumImpl(id, (int)val);
749                 break;
750             // string, bytes, object not allowed here.
751             default: {
752                 throw new IllegalArgumentException("Attempt to call write(long, long) with "
753                         + getFieldIdString(fieldId));
754             }
755         }
756     }
757 
758     /**
759      * Write a boolean value for the given fieldId.
760      *
761      * <p>If the field is not a bool field, an {@link IllegalStateException} will be thrown.
762      *
763      * @param fieldId The field identifier constant from the generated class.
764      * @param val The value.
765      */
write(long fieldId, boolean val)766     public void write(long fieldId, boolean val) {
767         assertNotCompacted();
768         final int id = (int)fieldId;
769 
770         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
771             // bool
772             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
773                 writeBoolImpl(id, val);
774                 break;
775             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
776             case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
777                 writeRepeatedBoolImpl(id, val);
778                 break;
779             // nothing else allowed
780             default: {
781                 throw new IllegalArgumentException("Attempt to call write(long, boolean) with "
782                         + getFieldIdString(fieldId));
783             }
784         }
785     }
786 
787     /**
788      * Write a string value for the given fieldId.
789      *
790      * <p>If the field is not a string field, an exception will be thrown.
791      *
792      * @param fieldId The field identifier constant from the generated class.
793      * @param val The value.
794      */
write(long fieldId, @Nullable String val)795     public void write(long fieldId, @Nullable String val) {
796         assertNotCompacted();
797         final int id = (int)fieldId;
798 
799         switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
800             // string
801             case (int)((FIELD_TYPE_STRING | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
802                 writeStringImpl(id, val);
803                 break;
804             case (int)((FIELD_TYPE_STRING | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
805             case (int)((FIELD_TYPE_STRING | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
806                 writeRepeatedStringImpl(id, val);
807                 break;
808             // nothing else allowed
809             default: {
810                 throw new IllegalArgumentException("Attempt to call write(long, String) with "
811                         + getFieldIdString(fieldId));
812             }
813         }
814     }
815 
816     /**
817      * Write a byte[] value for the given fieldId.
818      *
819      * <p>If the field is not a bytes or object field, an exception will be thrown.
820      *
821      * @param fieldId The field identifier constant from the generated class.
822      * @param val The value.
823      */
write(long fieldId, @Nullable byte[] val)824     public void write(long fieldId, @Nullable byte[] val) {
825         assertNotCompacted();
826         final int id = (int)fieldId;
827 
828         switch ((int) ((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
829             // bytes
830             case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
831                 writeBytesImpl(id, val);
832                 break;
833             case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
834             case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
835                 writeRepeatedBytesImpl(id, val);
836                 break;
837             // Object
838             case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
839                 writeObjectImpl(id, val);
840                 break;
841             case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
842             case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
843                 writeRepeatedObjectImpl(id, val);
844                 break;
845             // nothing else allowed
846             default: {
847                 throw new IllegalArgumentException("Attempt to call write(long, byte[]) with "
848                         + getFieldIdString(fieldId));
849             }
850         }
851     }
852 
853     /**
854      * Start a sub object.
855      *
856      * @param fieldId The field identifier constant from the generated class.
857      * @return The token to call {@link #end(long)} with.
858      */
start(long fieldId)859     public long start(long fieldId) {
860         assertNotCompacted();
861         final int id = (int)fieldId;
862 
863         if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_MESSAGE) {
864             final long count = fieldId & FIELD_COUNT_MASK;
865             if (count == FIELD_COUNT_SINGLE) {
866                 return startObjectImpl(id, false);
867             } else if (count == FIELD_COUNT_REPEATED || count == FIELD_COUNT_PACKED) {
868                 return startObjectImpl(id, true);
869             }
870         }
871         throw new IllegalArgumentException("Attempt to call start(long) with "
872                 + getFieldIdString(fieldId));
873     }
874 
875     /**
876      * End the object started by start() that returned token.
877      *
878      * @param token The token returned from {@link #start(long)}
879      */
end(long token)880     public void end(long token) {
881         endObjectImpl(token, getRepeatedFromToken(token));
882     }
883 
884     //
885     // proto3 type: double
886     // java type: double
887     // encoding: fixed64
888     // wire type: WIRE_TYPE_FIXED64
889     //
890 
891     /**
892      * Write a single proto "double" type field value.
893      *
894      * @deprecated Use {@link #write(long, double)} instead.
895      * @hide
896      */
897     @Deprecated
writeDouble(long fieldId, double val)898     public void writeDouble(long fieldId, double val) {
899         assertNotCompacted();
900         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE);
901 
902         writeDoubleImpl(id, val);
903     }
904 
writeDoubleImpl(int id, double val)905     private void writeDoubleImpl(int id, double val) {
906         if (val != 0) {
907             writeTag(id, WIRE_TYPE_FIXED64);
908             mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
909         }
910     }
911 
912     /**
913      * Write a single repeated proto "double" type field value.
914      *
915      * @deprecated Use {@link #write(long, double)} instead.
916      * @hide
917      */
918     @Deprecated
writeRepeatedDouble(long fieldId, double val)919     public void writeRepeatedDouble(long fieldId, double val) {
920         assertNotCompacted();
921         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_DOUBLE);
922 
923         writeRepeatedDoubleImpl(id, val);
924     }
925 
writeRepeatedDoubleImpl(int id, double val)926     private void writeRepeatedDoubleImpl(int id, double val) {
927         writeTag(id, WIRE_TYPE_FIXED64);
928         mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
929     }
930 
931     /**
932      * Write a list of packed proto "double" type field values.
933      *
934      * @deprecated Use {@link #write(long, double)} instead.
935      * @hide
936      */
937     @Deprecated
writePackedDouble(long fieldId, @Nullable double[] val)938     public void writePackedDouble(long fieldId, @Nullable double[] val) {
939         assertNotCompacted();
940         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
941 
942         final int N = val != null ? val.length : 0;
943         if (N > 0) {
944             writeKnownLengthHeader(id, N * 8);
945             for (int i=0; i<N; i++) {
946                 mBuffer.writeRawFixed64(Double.doubleToLongBits(val[i]));
947             }
948         }
949     }
950 
951     //
952     // proto3 type: float
953     // java type: float
954     // encoding: fixed32
955     // wire type: WIRE_TYPE_FIXED32
956     //
957 
958     /**
959      * Write a single proto "float" type field value.
960      *
961      * @deprecated Use {@link #write(long, float)} instead.
962      * @hide
963      */
964     @Deprecated
writeFloat(long fieldId, float val)965     public void writeFloat(long fieldId, float val) {
966         assertNotCompacted();
967         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT);
968 
969         writeFloatImpl(id, val);
970     }
971 
writeFloatImpl(int id, float val)972     private void writeFloatImpl(int id, float val) {
973         if (val != 0) {
974             writeTag(id, WIRE_TYPE_FIXED32);
975             mBuffer.writeRawFixed32(Float.floatToIntBits(val));
976         }
977     }
978 
979     /**
980      * Write a single repeated proto "float" type field value.
981      *
982      * @deprecated Use {@link #write(long, float)} instead.
983      * @hide
984      */
985     @Deprecated
writeRepeatedFloat(long fieldId, float val)986     public void writeRepeatedFloat(long fieldId, float val) {
987         assertNotCompacted();
988         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FLOAT);
989 
990         writeRepeatedFloatImpl(id, val);
991     }
992 
writeRepeatedFloatImpl(int id, float val)993     private void writeRepeatedFloatImpl(int id, float val) {
994         writeTag(id, WIRE_TYPE_FIXED32);
995         mBuffer.writeRawFixed32(Float.floatToIntBits(val));
996     }
997 
998     /**
999      * Write a list of packed proto "float" type field value.
1000      *
1001      * @deprecated Use {@link #write(long, float)} instead.
1002      * @hide
1003      */
1004     @Deprecated
writePackedFloat(long fieldId, @Nullable float[] val)1005     public void writePackedFloat(long fieldId, @Nullable float[] val) {
1006         assertNotCompacted();
1007         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
1008 
1009         final int N = val != null ? val.length : 0;
1010         if (N > 0) {
1011             writeKnownLengthHeader(id, N * 4);
1012             for (int i=0; i<N; i++) {
1013                 mBuffer.writeRawFixed32(Float.floatToIntBits(val[i]));
1014             }
1015         }
1016     }
1017 
1018     //
1019     // proto3 type: int32
1020     // java type: int
1021     // signed/unsigned: signed
1022     // encoding: varint
1023     // wire type: WIRE_TYPE_VARINT
1024     //
1025 
1026     /**
1027      * Writes a java int as an usigned varint.
1028      *
1029      * <p>The unadorned int32 type in protobuf is unfortunate because it
1030      * is stored in memory as a signed value, but encodes as unsigned
1031      * varints, which are formally always longs.  So here, we encode
1032      * negative values as 64 bits, which will get the sign-extension,
1033      * and positive values as 32 bits, which saves a marginal amount
1034      * of work in that it processes ints instead of longs.
1035      */
writeUnsignedVarintFromSignedInt(int val)1036     private void writeUnsignedVarintFromSignedInt(int val) {
1037         if (val >= 0) {
1038             mBuffer.writeRawVarint32(val);
1039         } else {
1040             mBuffer.writeRawVarint64(val);
1041         }
1042     }
1043 
1044     /**
1045      * Write a single proto "int32" type field value.
1046      *
1047      * <p>Note that these are stored in memory as signed values and written as unsigned
1048      * varints, which if negative, are 10 bytes long. If you know the data is likely
1049      * to be negative, use "sint32".
1050      *
1051      * @deprecated Use {@link #write(long, int)} instead.
1052      * @hide
1053      */
1054     @Deprecated
writeInt32(long fieldId, int val)1055     public void writeInt32(long fieldId, int val) {
1056         assertNotCompacted();
1057         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT32);
1058 
1059         writeInt32Impl(id, val);
1060     }
1061 
writeInt32Impl(int id, int val)1062     private void writeInt32Impl(int id, int val) {
1063         if (val != 0) {
1064             writeTag(id, WIRE_TYPE_VARINT);
1065             writeUnsignedVarintFromSignedInt(val);
1066         }
1067     }
1068 
1069     /**
1070      * Write a single repeated proto "int32" type field value.
1071      *
1072      * <p>Note that these are stored in memory as signed values and written as unsigned
1073      * varints, which if negative, are 10 bytes long. If you know the data is likely
1074      * to be negative, use "sint32".
1075      *
1076      * @deprecated Use {@link #write(long, int)} instead.
1077      * @hide
1078      */
1079     @Deprecated
writeRepeatedInt32(long fieldId, int val)1080     public void writeRepeatedInt32(long fieldId, int val) {
1081         assertNotCompacted();
1082         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT32);
1083 
1084         writeRepeatedInt32Impl(id, val);
1085     }
1086 
writeRepeatedInt32Impl(int id, int val)1087     private void writeRepeatedInt32Impl(int id, int val) {
1088         writeTag(id, WIRE_TYPE_VARINT);
1089         writeUnsignedVarintFromSignedInt(val);
1090     }
1091 
1092     /**
1093      * Write a list of packed proto "int32" type field value.
1094      *
1095      * <p>Note that these are stored in memory as signed values and written as unsigned
1096      * varints, which if negative, are 10 bytes long. If you know the data is likely
1097      * to be negative, use "sint32".
1098      *
1099      * @deprecated Use {@link #write(long, int)} instead.
1100      * @hide
1101      */
1102     @Deprecated
writePackedInt32(long fieldId, @Nullable int[] val)1103     public void writePackedInt32(long fieldId, @Nullable int[] val) {
1104         assertNotCompacted();
1105         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
1106 
1107         final int N = val != null ? val.length : 0;
1108         if (N > 0) {
1109             int size = 0;
1110             for (int i=0; i<N; i++) {
1111                 final int v = val[i];
1112                 size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
1113             }
1114             writeKnownLengthHeader(id, size);
1115             for (int i=0; i<N; i++) {
1116                 writeUnsignedVarintFromSignedInt(val[i]);
1117             }
1118         }
1119     }
1120 
1121     //
1122     // proto3 type: int64
1123     // java type: int
1124     // signed/unsigned: signed
1125     // encoding: varint
1126     // wire type: WIRE_TYPE_VARINT
1127     //
1128 
1129     /**
1130      * Write a single proto "int64" type field value.
1131      *
1132      * @deprecated Use {@link #write(long, long)} instead.
1133      * @hide
1134      */
1135     @Deprecated
writeInt64(long fieldId, long val)1136     public void writeInt64(long fieldId, long val) {
1137         assertNotCompacted();
1138         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT64);
1139 
1140         writeInt64Impl(id, val);
1141     }
1142 
writeInt64Impl(int id, long val)1143     private void writeInt64Impl(int id, long val) {
1144         if (val != 0) {
1145             writeTag(id, WIRE_TYPE_VARINT);
1146             mBuffer.writeRawVarint64(val);
1147         }
1148     }
1149 
1150     /**
1151      * Write a single repeated proto "int64" type field value.
1152      *
1153      * @deprecated Use {@link #write(long, long)} instead.
1154      * @hide
1155      */
1156     @Deprecated
writeRepeatedInt64(long fieldId, long val)1157     public void writeRepeatedInt64(long fieldId, long val) {
1158         assertNotCompacted();
1159         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT64);
1160 
1161         writeRepeatedInt64Impl(id, val);
1162     }
1163 
writeRepeatedInt64Impl(int id, long val)1164     private void writeRepeatedInt64Impl(int id, long val) {
1165         writeTag(id, WIRE_TYPE_VARINT);
1166         mBuffer.writeRawVarint64(val);
1167     }
1168 
1169     /**
1170      * Write a list of packed proto "int64" type field value.
1171      *
1172      * @deprecated Use {@link #write(long, long)} instead.
1173      * @hide
1174      */
1175     @Deprecated
writePackedInt64(long fieldId, @Nullable long[] val)1176     public void writePackedInt64(long fieldId, @Nullable long[] val) {
1177         assertNotCompacted();
1178         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
1179 
1180         final int N = val != null ? val.length : 0;
1181         if (N > 0) {
1182             int size = 0;
1183             for (int i=0; i<N; i++) {
1184                 size += EncodedBuffer.getRawVarint64Size(val[i]);
1185             }
1186             writeKnownLengthHeader(id, size);
1187             for (int i=0; i<N; i++) {
1188                 mBuffer.writeRawVarint64(val[i]);
1189             }
1190         }
1191     }
1192 
1193     //
1194     // proto3 type: uint32
1195     // java type: int
1196     // signed/unsigned: unsigned
1197     // encoding: varint
1198     // wire type: WIRE_TYPE_VARINT
1199     //
1200 
1201     /**
1202      * Write a single proto "uint32" type field value.
1203      *
1204      * @deprecated Use {@link #write(long, int)} instead.
1205      * @hide
1206      */
1207     @Deprecated
writeUInt32(long fieldId, int val)1208     public void writeUInt32(long fieldId, int val) {
1209         assertNotCompacted();
1210         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32);
1211 
1212         writeUInt32Impl(id, val);
1213     }
1214 
writeUInt32Impl(int id, int val)1215     private void writeUInt32Impl(int id, int val) {
1216         if (val != 0) {
1217             writeTag(id, WIRE_TYPE_VARINT);
1218             mBuffer.writeRawVarint32(val);
1219         }
1220     }
1221 
1222     /**
1223      * Write a single repeated proto "uint32" type field value.
1224      *
1225      * @deprecated Use {@link #write(long, int)} instead.
1226      * @hide
1227      */
1228     @Deprecated
writeRepeatedUInt32(long fieldId, int val)1229     public void writeRepeatedUInt32(long fieldId, int val) {
1230         assertNotCompacted();
1231         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT32);
1232 
1233         writeRepeatedUInt32Impl(id, val);
1234     }
1235 
writeRepeatedUInt32Impl(int id, int val)1236     private void writeRepeatedUInt32Impl(int id, int val) {
1237         writeTag(id, WIRE_TYPE_VARINT);
1238         mBuffer.writeRawVarint32(val);
1239     }
1240 
1241     /**
1242      * Write a list of packed proto "uint32" type field value.
1243      *
1244      * @deprecated Use {@link #write(long, int)} instead.
1245      * @hide
1246      */
1247     @Deprecated
writePackedUInt32(long fieldId, @Nullable int[] val)1248     public void writePackedUInt32(long fieldId, @Nullable int[] val) {
1249         assertNotCompacted();
1250         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
1251 
1252         final int N = val != null ? val.length : 0;
1253         if (N > 0) {
1254             int size = 0;
1255             for (int i=0; i<N; i++) {
1256                 size += EncodedBuffer.getRawVarint32Size(val[i]);
1257             }
1258             writeKnownLengthHeader(id, size);
1259             for (int i=0; i<N; i++) {
1260                 mBuffer.writeRawVarint32(val[i]);
1261             }
1262         }
1263     }
1264 
1265     //
1266     // proto3 type: uint64
1267     // java type: int
1268     // signed/unsigned: unsigned
1269     // encoding: varint
1270     // wire type: WIRE_TYPE_VARINT
1271     //
1272 
1273     /**
1274      * Write a single proto "uint64" type field value.
1275      *
1276      * @deprecated Use {@link #write(long, long)} instead.
1277      * @hide
1278      */
1279     @Deprecated
writeUInt64(long fieldId, long val)1280     public void writeUInt64(long fieldId, long val) {
1281         assertNotCompacted();
1282         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64);
1283 
1284         writeUInt64Impl(id, val);
1285     }
1286 
writeUInt64Impl(int id, long val)1287     private void writeUInt64Impl(int id, long val) {
1288         if (val != 0) {
1289             writeTag(id, WIRE_TYPE_VARINT);
1290             mBuffer.writeRawVarint64(val);
1291         }
1292     }
1293 
1294     /**
1295      * Write a single proto "uint64" type field value.
1296      *
1297      * @deprecated Use {@link #write(long, long)} instead.
1298      * @hide
1299      */
1300     @Deprecated
writeRepeatedUInt64(long fieldId, long val)1301     public void writeRepeatedUInt64(long fieldId, long val) {
1302         assertNotCompacted();
1303         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT64);
1304 
1305         writeRepeatedUInt64Impl(id, val);
1306     }
1307 
writeRepeatedUInt64Impl(int id, long val)1308     private void writeRepeatedUInt64Impl(int id, long val) {
1309         writeTag(id, WIRE_TYPE_VARINT);
1310         mBuffer.writeRawVarint64(val);
1311     }
1312 
1313     /**
1314      * Write a single proto "uint64" type field value.
1315      *
1316      * @deprecated Use {@link #write(long, long)} instead.
1317      * @hide
1318      */
1319     @Deprecated
writePackedUInt64(long fieldId, @Nullable long[] val)1320     public void writePackedUInt64(long fieldId, @Nullable long[] val) {
1321         assertNotCompacted();
1322         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
1323 
1324         final int N = val != null ? val.length : 0;
1325         if (N > 0) {
1326             int size = 0;
1327             for (int i=0; i<N; i++) {
1328                 size += EncodedBuffer.getRawVarint64Size(val[i]);
1329             }
1330             writeKnownLengthHeader(id, size);
1331             for (int i=0; i<N; i++) {
1332                 mBuffer.writeRawVarint64(val[i]);
1333             }
1334         }
1335     }
1336 
1337     //
1338     // proto3 type: sint32
1339     // java type: int
1340     // signed/unsigned: signed
1341     // encoding: zig-zag
1342     // wire type: WIRE_TYPE_VARINT
1343     //
1344 
1345     /**
1346      * Write a single proto "sint32" type field value.
1347      *
1348      * @deprecated Use {@link #write(long, int)} instead.
1349      * @hide
1350      */
1351     @Deprecated
writeSInt32(long fieldId, int val)1352     public void writeSInt32(long fieldId, int val) {
1353         assertNotCompacted();
1354         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32);
1355 
1356         writeSInt32Impl(id, val);
1357     }
1358 
writeSInt32Impl(int id, int val)1359     private void writeSInt32Impl(int id, int val) {
1360         if (val != 0) {
1361             writeTag(id, WIRE_TYPE_VARINT);
1362             mBuffer.writeRawZigZag32(val);
1363         }
1364     }
1365 
1366     /**
1367      * Write a single repeated proto "sint32" type field value.
1368      *
1369      * @deprecated Use {@link #write(long, int)} instead.
1370      * @hide
1371      */
1372     @Deprecated
writeRepeatedSInt32(long fieldId, int val)1373     public void writeRepeatedSInt32(long fieldId, int val) {
1374         assertNotCompacted();
1375         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT32);
1376 
1377         writeRepeatedSInt32Impl(id, val);
1378     }
1379 
writeRepeatedSInt32Impl(int id, int val)1380     private void writeRepeatedSInt32Impl(int id, int val) {
1381         writeTag(id, WIRE_TYPE_VARINT);
1382         mBuffer.writeRawZigZag32(val);
1383     }
1384 
1385     /**
1386      * Write a list of packed proto "sint32" type field value.
1387      *
1388      * @deprecated Use {@link #write(long, int)} instead.
1389      * @hide
1390      */
1391     @Deprecated
writePackedSInt32(long fieldId, @Nullable int[] val)1392     public void writePackedSInt32(long fieldId, @Nullable int[] val) {
1393         assertNotCompacted();
1394         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
1395 
1396         final int N = val != null ? val.length : 0;
1397         if (N > 0) {
1398             int size = 0;
1399             for (int i=0; i<N; i++) {
1400                 size += EncodedBuffer.getRawZigZag32Size(val[i]);
1401             }
1402             writeKnownLengthHeader(id, size);
1403             for (int i=0; i<N; i++) {
1404                 mBuffer.writeRawZigZag32(val[i]);
1405             }
1406         }
1407     }
1408 
1409     //
1410     // proto3 type: sint64
1411     // java type: int
1412     // signed/unsigned: signed
1413     // encoding: zig-zag
1414     // wire type: WIRE_TYPE_VARINT
1415     //
1416 
1417     /**
1418      * Write a single proto "sint64" type field value.
1419      *
1420      * @deprecated Use {@link #write(long, long)} instead.
1421      * @hide
1422      */
1423     @Deprecated
writeSInt64(long fieldId, long val)1424     public void writeSInt64(long fieldId, long val) {
1425         assertNotCompacted();
1426         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64);
1427 
1428         writeSInt64Impl(id, val);
1429     }
1430 
writeSInt64Impl(int id, long val)1431     private void writeSInt64Impl(int id, long val) {
1432         if (val != 0) {
1433             writeTag(id, WIRE_TYPE_VARINT);
1434             mBuffer.writeRawZigZag64(val);
1435         }
1436     }
1437 
1438     /**
1439      * Write a single repeated proto "sint64" type field value.
1440      *
1441      * @deprecated Use {@link #write(long, long)} instead.
1442      * @hide
1443      */
1444     @Deprecated
writeRepeatedSInt64(long fieldId, long val)1445     public void writeRepeatedSInt64(long fieldId, long val) {
1446         assertNotCompacted();
1447         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT64);
1448 
1449         writeRepeatedSInt64Impl(id, val);
1450     }
1451 
writeRepeatedSInt64Impl(int id, long val)1452     private void writeRepeatedSInt64Impl(int id, long val) {
1453         writeTag(id, WIRE_TYPE_VARINT);
1454         mBuffer.writeRawZigZag64(val);
1455     }
1456 
1457     /**
1458      * Write a list of packed proto "sint64" type field value.
1459      *
1460      * @deprecated Use {@link #write(long, long)} instead.
1461      * @hide
1462      */
1463     @Deprecated
writePackedSInt64(long fieldId, @Nullable long[] val)1464     public void writePackedSInt64(long fieldId, @Nullable long[] val) {
1465         assertNotCompacted();
1466         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
1467 
1468         final int N = val != null ? val.length : 0;
1469         if (N > 0) {
1470             int size = 0;
1471             for (int i=0; i<N; i++) {
1472                 size += EncodedBuffer.getRawZigZag64Size(val[i]);
1473             }
1474             writeKnownLengthHeader(id, size);
1475             for (int i=0; i<N; i++) {
1476                 mBuffer.writeRawZigZag64(val[i]);
1477             }
1478         }
1479     }
1480 
1481     //
1482     // proto3 type: fixed32
1483     // java type: int
1484     // encoding: little endian
1485     // wire type: WIRE_TYPE_FIXED32
1486     //
1487 
1488     /**
1489      * Write a single proto "fixed32" type field value.
1490      *
1491      * @deprecated Use {@link #write(long, int)} instead.
1492      * @hide
1493      */
1494     @Deprecated
writeFixed32(long fieldId, int val)1495     public void writeFixed32(long fieldId, int val) {
1496         assertNotCompacted();
1497         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32);
1498 
1499         writeFixed32Impl(id, val);
1500     }
1501 
writeFixed32Impl(int id, int val)1502     private void writeFixed32Impl(int id, int val) {
1503         if (val != 0) {
1504             writeTag(id, WIRE_TYPE_FIXED32);
1505             mBuffer.writeRawFixed32(val);
1506         }
1507     }
1508 
1509     /**
1510      * Write a single repeated proto "fixed32" type field value.
1511      *
1512      * @deprecated Use {@link #write(long, int)} instead.
1513      * @hide
1514      */
1515     @Deprecated
writeRepeatedFixed32(long fieldId, int val)1516     public void writeRepeatedFixed32(long fieldId, int val) {
1517         assertNotCompacted();
1518         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED32);
1519 
1520         writeRepeatedFixed32Impl(id, val);
1521     }
1522 
writeRepeatedFixed32Impl(int id, int val)1523     private void writeRepeatedFixed32Impl(int id, int val) {
1524         writeTag(id, WIRE_TYPE_FIXED32);
1525         mBuffer.writeRawFixed32(val);
1526     }
1527 
1528     /**
1529      * Write a list of packed proto "fixed32" type field value.
1530      *
1531      * @deprecated Use {@link #write(long, int)} instead.
1532      * @hide
1533      */
1534     @Deprecated
writePackedFixed32(long fieldId, @Nullable int[] val)1535     public void writePackedFixed32(long fieldId, @Nullable int[] val) {
1536         assertNotCompacted();
1537         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
1538 
1539         final int N = val != null ? val.length : 0;
1540         if (N > 0) {
1541             writeKnownLengthHeader(id, N * 4);
1542             for (int i=0; i<N; i++) {
1543                 mBuffer.writeRawFixed32(val[i]);
1544             }
1545         }
1546     }
1547 
1548     //
1549     // proto3 type: fixed64
1550     // java type: long
1551     // encoding: fixed64
1552     // wire type: WIRE_TYPE_FIXED64
1553     //
1554 
1555     /**
1556      * Write a single proto "fixed64" type field value.
1557      *
1558      * @deprecated Use {@link #write(long, long)} instead.
1559      * @hide
1560      */
1561     @Deprecated
writeFixed64(long fieldId, long val)1562     public void writeFixed64(long fieldId, long val) {
1563         assertNotCompacted();
1564         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64);
1565 
1566         writeFixed64Impl(id, val);
1567     }
1568 
writeFixed64Impl(int id, long val)1569     private void writeFixed64Impl(int id, long val) {
1570         if (val != 0) {
1571             writeTag(id, WIRE_TYPE_FIXED64);
1572             mBuffer.writeRawFixed64(val);
1573         }
1574     }
1575 
1576     /**
1577      * Write a single repeated proto "fixed64" type field value.
1578      *
1579      * @deprecated Use {@link #write(long, long)} instead.
1580      * @hide
1581      */
1582     @Deprecated
writeRepeatedFixed64(long fieldId, long val)1583     public void writeRepeatedFixed64(long fieldId, long val) {
1584         assertNotCompacted();
1585         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64);
1586 
1587         writeRepeatedFixed64Impl(id, val);
1588     }
1589 
writeRepeatedFixed64Impl(int id, long val)1590     private void writeRepeatedFixed64Impl(int id, long val) {
1591         writeTag(id, WIRE_TYPE_FIXED64);
1592         mBuffer.writeRawFixed64(val);
1593     }
1594 
1595     /**
1596      * Write a list of packed proto "fixed64" type field value.
1597      *
1598      * @deprecated Use {@link #write(long, long)} instead.
1599      * @hide
1600      */
1601     @Deprecated
writePackedFixed64(long fieldId, @Nullable long[] val)1602     public void writePackedFixed64(long fieldId, @Nullable long[] val) {
1603         assertNotCompacted();
1604         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
1605 
1606         final int N = val != null ? val.length : 0;
1607         if (N > 0) {
1608             writeKnownLengthHeader(id, N * 8);
1609             for (int i=0; i<N; i++) {
1610                 mBuffer.writeRawFixed64(val[i]);
1611             }
1612         }
1613     }
1614 
1615     //
1616     // proto3 type: sfixed32
1617     // java type: int
1618     // encoding: little endian
1619     // wire type: WIRE_TYPE_FIXED32
1620     //
1621     /**
1622      * Write a single proto "sfixed32" type field value.
1623      *
1624      * @deprecated Use {@link #write(long, int)} instead.
1625      * @hide
1626      */
1627     @Deprecated
writeSFixed32(long fieldId, int val)1628     public void writeSFixed32(long fieldId, int val) {
1629         assertNotCompacted();
1630         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32);
1631 
1632         writeSFixed32Impl(id, val);
1633     }
1634 
writeSFixed32Impl(int id, int val)1635     private void writeSFixed32Impl(int id, int val) {
1636         if (val != 0) {
1637             writeTag(id, WIRE_TYPE_FIXED32);
1638             mBuffer.writeRawFixed32(val);
1639         }
1640     }
1641 
1642     /**
1643      * Write a single repeated proto "sfixed32" type field value.
1644      *
1645      * @deprecated Use {@link #write(long, int)} instead.
1646      * @hide
1647      */
1648     @Deprecated
writeRepeatedSFixed32(long fieldId, int val)1649     public void writeRepeatedSFixed32(long fieldId, int val) {
1650         assertNotCompacted();
1651         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED32);
1652 
1653         writeRepeatedSFixed32Impl(id, val);
1654     }
1655 
writeRepeatedSFixed32Impl(int id, int val)1656     private void writeRepeatedSFixed32Impl(int id, int val) {
1657         writeTag(id, WIRE_TYPE_FIXED32);
1658         mBuffer.writeRawFixed32(val);
1659     }
1660 
1661     /**
1662      * Write a list of packed proto "sfixed32" type field value.
1663      *
1664      * @deprecated Use {@link #write(long, int)} instead.
1665      * @hide
1666      */
1667     @Deprecated
writePackedSFixed32(long fieldId, @Nullable int[] val)1668     public void writePackedSFixed32(long fieldId, @Nullable int[] val) {
1669         assertNotCompacted();
1670         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
1671 
1672         final int N = val != null ? val.length : 0;
1673         if (N > 0) {
1674             writeKnownLengthHeader(id, N * 4);
1675             for (int i=0; i<N; i++) {
1676                 mBuffer.writeRawFixed32(val[i]);
1677             }
1678         }
1679     }
1680 
1681     //
1682     // proto3 type: sfixed64
1683     // java type: long
1684     // encoding: little endian
1685     // wire type: WIRE_TYPE_FIXED64
1686     //
1687 
1688     /**
1689      * Write a single proto "sfixed64" type field value.
1690      *
1691      * @deprecated Use {@link #write(long, long)} instead.
1692      * @hide
1693      */
1694     @Deprecated
writeSFixed64(long fieldId, long val)1695     public void writeSFixed64(long fieldId, long val) {
1696         assertNotCompacted();
1697         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64);
1698 
1699         writeSFixed64Impl(id, val);
1700     }
1701 
writeSFixed64Impl(int id, long val)1702     private void writeSFixed64Impl(int id, long val) {
1703         if (val != 0) {
1704             writeTag(id, WIRE_TYPE_FIXED64);
1705             mBuffer.writeRawFixed64(val);
1706         }
1707     }
1708 
1709     /**
1710      * Write a single repeated proto "sfixed64" type field value.
1711      *
1712      * @deprecated Use {@link #write(long, long)} instead.
1713      * @hide
1714      */
1715     @Deprecated
writeRepeatedSFixed64(long fieldId, long val)1716     public void writeRepeatedSFixed64(long fieldId, long val) {
1717         assertNotCompacted();
1718         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64);
1719 
1720         writeRepeatedSFixed64Impl(id, val);
1721     }
1722 
writeRepeatedSFixed64Impl(int id, long val)1723     private void writeRepeatedSFixed64Impl(int id, long val) {
1724         writeTag(id, WIRE_TYPE_FIXED64);
1725         mBuffer.writeRawFixed64(val);
1726     }
1727 
1728     /**
1729      * Write a list of packed proto "sfixed64" type field value.
1730      *
1731      * @deprecated Use {@link #write(long, long)} instead.
1732      * @hide
1733      */
1734     @Deprecated
writePackedSFixed64(long fieldId, @Nullable long[] val)1735     public void writePackedSFixed64(long fieldId, @Nullable long[] val) {
1736         assertNotCompacted();
1737         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
1738 
1739         final int N = val != null ? val.length : 0;
1740         if (N > 0) {
1741             writeKnownLengthHeader(id, N * 8);
1742             for (int i=0; i<N; i++) {
1743                 mBuffer.writeRawFixed64(val[i]);
1744             }
1745         }
1746     }
1747 
1748     //
1749     // proto3 type: bool
1750     // java type: boolean
1751     // encoding: varint
1752     // wire type: WIRE_TYPE_VARINT
1753     //
1754 
1755     /**
1756      * Write a single proto "bool" type field value.
1757      *
1758      * @deprecated Use {@link #write(long, boolean)} instead.
1759      * @hide
1760      */
1761     @Deprecated
writeBool(long fieldId, boolean val)1762     public void writeBool(long fieldId, boolean val) {
1763         assertNotCompacted();
1764         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL);
1765 
1766         writeBoolImpl(id, val);
1767     }
1768 
writeBoolImpl(int id, boolean val)1769     private void writeBoolImpl(int id, boolean val) {
1770         if (val) {
1771             writeTag(id, WIRE_TYPE_VARINT);
1772             // 0 and 1 are the same as their varint counterparts
1773             mBuffer.writeRawByte((byte)1);
1774         }
1775     }
1776 
1777     /**
1778      * Write a single repeated proto "bool" type field value.
1779      *
1780      * @deprecated Use {@link #write(long, boolean)} instead.
1781      * @hide
1782      */
1783     @Deprecated
writeRepeatedBool(long fieldId, boolean val)1784     public void writeRepeatedBool(long fieldId, boolean val) {
1785         assertNotCompacted();
1786         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL);
1787 
1788         writeRepeatedBoolImpl(id, val);
1789     }
1790 
writeRepeatedBoolImpl(int id, boolean val)1791     private void writeRepeatedBoolImpl(int id, boolean val) {
1792         writeTag(id, WIRE_TYPE_VARINT);
1793         mBuffer.writeRawByte((byte)(val ? 1 : 0));
1794     }
1795 
1796     /**
1797      * Write a list of packed proto "bool" type field value.
1798      *
1799      * @deprecated Use {@link #write(long, boolean)} instead.
1800      * @hide
1801      */
1802     @Deprecated
writePackedBool(long fieldId, @Nullable boolean[] val)1803     public void writePackedBool(long fieldId, @Nullable boolean[] val) {
1804         assertNotCompacted();
1805         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
1806 
1807         final int N = val != null ? val.length : 0;
1808         if (N > 0) {
1809             // Write the header
1810             writeKnownLengthHeader(id, N);
1811 
1812             // Write the data
1813             for (int i=0; i<N; i++) {
1814                 // 0 and 1 are the same as their varint counterparts
1815                 mBuffer.writeRawByte((byte)(val[i] ? 1 : 0));
1816             }
1817         }
1818     }
1819 
1820     //
1821     // proto3 type: string
1822     // java type: String
1823     // encoding: utf-8
1824     // wire type: WIRE_TYPE_LENGTH_DELIMITED
1825     //
1826 
1827     /**
1828      * Write a single proto "string" type field value.
1829      *
1830      * @deprecated Use {@link #write(long, String)} instead.
1831      * @hide
1832      */
1833     @Deprecated
writeString(long fieldId, @Nullable String val)1834     public void writeString(long fieldId, @Nullable String val) {
1835         assertNotCompacted();
1836         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
1837 
1838         writeStringImpl(id, val);
1839     }
1840 
writeStringImpl(int id, String val)1841     private void writeStringImpl(int id, String val) {
1842         if (val != null && val.length() > 0) {
1843             writeUtf8String(id, val);
1844         }
1845     }
1846 
1847     /**
1848      * Write a single repeated proto "string" type field value.
1849      *
1850      * @deprecated Use {@link #write(long, String)} instead.
1851      * @hide
1852      */
1853     @Deprecated
writeRepeatedString(long fieldId, @Nullable String val)1854     public void writeRepeatedString(long fieldId, @Nullable String val) {
1855         assertNotCompacted();
1856         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
1857 
1858         writeRepeatedStringImpl(id, val);
1859     }
1860 
writeRepeatedStringImpl(int id, String val)1861     private void writeRepeatedStringImpl(int id, String val) {
1862         if (val == null || val.length() == 0) {
1863             writeKnownLengthHeader(id, 0);
1864         } else {
1865             writeUtf8String(id, val);
1866         }
1867     }
1868 
1869     /**
1870      * Write a list of packed proto "string" type field value.
1871      */
writeUtf8String(int id, String val)1872     private void writeUtf8String(int id, String val) {
1873         // TODO: Is it worth converting by hand in order to not allocate?
1874         try {
1875             final byte[] buf = val.getBytes("UTF-8");
1876             writeKnownLengthHeader(id, buf.length);
1877             mBuffer.writeRawBuffer(buf);
1878         } catch (UnsupportedEncodingException ex) {
1879             throw new RuntimeException("not possible");
1880         }
1881     }
1882 
1883     //
1884     // proto3 type: bytes
1885     // java type: byte[]
1886     // encoding: varint
1887     // wire type: WIRE_TYPE_VARINT
1888     //
1889 
1890     /**
1891      * Write a single proto "bytes" type field value.
1892      *
1893      * @deprecated Use {@link #write(long, byte[])} instead.
1894      * @hide
1895      */
1896     @Deprecated
writeBytes(long fieldId, @Nullable byte[] val)1897     public void writeBytes(long fieldId, @Nullable byte[] val) {
1898         assertNotCompacted();
1899         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
1900 
1901         writeBytesImpl(id, val);
1902     }
1903 
writeBytesImpl(int id, byte[] val)1904     private void writeBytesImpl(int id, byte[] val) {
1905         if (val != null && val.length > 0) {
1906             writeKnownLengthHeader(id, val.length);
1907             mBuffer.writeRawBuffer(val);
1908         }
1909     }
1910 
1911     /**
1912      * Write a single repeated proto "bytes" type field value.
1913      *
1914      * @deprecated Use {@link #write(long, byte[])} instead.
1915      * @hide
1916      */
1917     @Deprecated
writeRepeatedBytes(long fieldId, @Nullable byte[] val)1918     public void writeRepeatedBytes(long fieldId, @Nullable byte[] val) {
1919         assertNotCompacted();
1920         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
1921 
1922         writeRepeatedBytesImpl(id, val);
1923     }
1924 
writeRepeatedBytesImpl(int id, byte[] val)1925     private void writeRepeatedBytesImpl(int id, byte[] val) {
1926         writeKnownLengthHeader(id, val == null ? 0 : val.length);
1927         mBuffer.writeRawBuffer(val);
1928     }
1929 
1930     //
1931     // proto3 type: enum
1932     // java type: int
1933     // signed/unsigned: unsigned
1934     // encoding: varint
1935     // wire type: WIRE_TYPE_VARINT
1936     //
1937 
1938     /**
1939      * Write a single proto enum type field value.
1940      *
1941      * @deprecated Use {@link #write(long, int)} instead.
1942      * @hide
1943      */
1944     @Deprecated
writeEnum(long fieldId, int val)1945     public void writeEnum(long fieldId, int val) {
1946         assertNotCompacted();
1947         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM);
1948 
1949         writeEnumImpl(id, val);
1950     }
1951 
writeEnumImpl(int id, int val)1952     private void writeEnumImpl(int id, int val) {
1953         if (val != 0) {
1954             writeTag(id, WIRE_TYPE_VARINT);
1955             writeUnsignedVarintFromSignedInt(val);
1956         }
1957     }
1958 
1959     /**
1960      * Write a single repeated proto enum type field value.
1961      *
1962      * @deprecated Use {@link #write(long, int)} instead.
1963      * @hide
1964      */
1965     @Deprecated
writeRepeatedEnum(long fieldId, int val)1966     public void writeRepeatedEnum(long fieldId, int val) {
1967         assertNotCompacted();
1968         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_ENUM);
1969 
1970         writeRepeatedEnumImpl(id, val);
1971     }
1972 
writeRepeatedEnumImpl(int id, int val)1973     private void writeRepeatedEnumImpl(int id, int val) {
1974         writeTag(id, WIRE_TYPE_VARINT);
1975         writeUnsignedVarintFromSignedInt(val);
1976     }
1977 
1978     /**
1979      * Write a list of packed proto enum type field value.
1980      *
1981      * @deprecated Use {@link #write(long, int)} instead.
1982      * @hide
1983      */
1984     @Deprecated
writePackedEnum(long fieldId, @Nullable int[] val)1985     public void writePackedEnum(long fieldId, @Nullable int[] val) {
1986         assertNotCompacted();
1987         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
1988 
1989         final int N = val != null ? val.length : 0;
1990         if (N > 0) {
1991             int size = 0;
1992             for (int i=0; i<N; i++) {
1993                 final int v = val[i];
1994                 size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
1995             }
1996             writeKnownLengthHeader(id, size);
1997             for (int i=0; i<N; i++) {
1998                 writeUnsignedVarintFromSignedInt(val[i]);
1999             }
2000         }
2001     }
2002 
2003 
2004     /**
2005      * Start a child object.
2006      *
2007      * Returns a token which should be passed to endObject.  Calls to endObject must be
2008      * nested properly.
2009      *
2010      * @deprecated Use {@link #start(long)} instead.
2011      * @hide
2012      */
2013     @Deprecated
startObject(long fieldId)2014     public long startObject(long fieldId) {
2015         assertNotCompacted();
2016         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
2017 
2018         return startObjectImpl(id, false);
2019     }
2020 
2021     /**
2022      * End a child object. Pass in the token from the correspoinding startObject call.
2023      *
2024      * @deprecated Use {@link #end(long)} instead.
2025      * @hide
2026      */
2027     @Deprecated
endObject(long token)2028     public void endObject(long token) {
2029         assertNotCompacted();
2030 
2031         endObjectImpl(token, false);
2032     }
2033 
2034     /**
2035      * Start a repeated child object.
2036      *
2037      * Returns a token which should be passed to endObject.  Calls to endObject must be
2038      * nested properly.
2039      *
2040      * @deprecated Use {@link #start(long)} instead.
2041      * @hide
2042      */
2043     @Deprecated
startRepeatedObject(long fieldId)2044     public long startRepeatedObject(long fieldId) {
2045         assertNotCompacted();
2046         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
2047 
2048         return startObjectImpl(id, true);
2049     }
2050 
2051     /**
2052      * End a child object. Pass in the token from the correspoinding startRepeatedObject call.
2053      *
2054      * @deprecated Use {@link #end(long)} instead.
2055      * @hide
2056      */
2057     @Deprecated
endRepeatedObject(long token)2058     public void endRepeatedObject(long token) {
2059         assertNotCompacted();
2060 
2061         endObjectImpl(token, true);
2062     }
2063 
2064     /**
2065      * Common implementation of startObject and startRepeatedObject.
2066      */
startObjectImpl(final int id, boolean repeated)2067     private long startObjectImpl(final int id, boolean repeated) {
2068         writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
2069         final int sizePos = mBuffer.getWritePos();
2070         mDepth++;
2071         mNextObjectId--;
2072 
2073         // Write the previous token, giving us a stack of expected tokens.
2074         // After endObject returns, the first fixed32 becomeschildRawSize (set in endObject)
2075         // and the second one becomes childEncodedSize (set in editEncodedSize).
2076         mBuffer.writeRawFixed32((int)(mExpectedObjectToken >> 32));
2077         mBuffer.writeRawFixed32((int)mExpectedObjectToken);
2078 
2079         long old = mExpectedObjectToken;
2080 
2081         mExpectedObjectToken = makeToken(getTagSize(id), repeated, mDepth, mNextObjectId, sizePos);
2082         return mExpectedObjectToken;
2083     }
2084 
2085     /**
2086      * Common implementation of endObject and endRepeatedObject.
2087      */
endObjectImpl(long token, boolean repeated)2088     private void endObjectImpl(long token, boolean repeated) {
2089         // The upper 32 bits of the token is the depth of startObject /
2090         // endObject calls.  We could get aritrarily sophisticated, but
2091         // that's enough to prevent the common error of missing an
2092         // endObject somewhere.
2093         // The lower 32 bits of the token is the offset in the buffer
2094         // at which to write the size.
2095         final int depth = getDepthFromToken(token);
2096         final boolean expectedRepeated = getRepeatedFromToken(token);
2097         final int sizePos = getOffsetFromToken(token);
2098         final int childRawSize = mBuffer.getWritePos() - sizePos - 8;
2099 
2100         if (repeated != expectedRepeated) {
2101             if (repeated) {
2102                 throw new IllegalArgumentException("endRepeatedObject called where endObject should"
2103                         + " have been");
2104             } else {
2105                 throw new IllegalArgumentException("endObject called where endRepeatedObject should"
2106                         + " have been");
2107             }
2108         }
2109 
2110         // Check that we're getting the token and depth that we are expecting.
2111         if ((mDepth & 0x01ff) != depth || mExpectedObjectToken != token) {
2112             // This text of exception is united tested.  That test also implicity checks
2113             // that we're tracking the objectIds and depths correctly.
2114             throw new IllegalArgumentException("Mismatched startObject/endObject calls."
2115                     + " Current depth " + mDepth
2116                     + " token=" + token2String(token)
2117                     + " expectedToken=" + token2String(mExpectedObjectToken));
2118         }
2119 
2120         // Get the next expected token that we stashed away in the buffer.
2121         mExpectedObjectToken = (((long)mBuffer.getRawFixed32At(sizePos)) << 32)
2122                 | (0x0ffffffffL & (long)mBuffer.getRawFixed32At(sizePos+4));
2123 
2124         mDepth--;
2125         if (childRawSize > 0) {
2126             mBuffer.editRawFixed32(sizePos, -childRawSize);
2127             mBuffer.editRawFixed32(sizePos+4, -1);
2128         } else if (repeated) {
2129             mBuffer.editRawFixed32(sizePos, 0);
2130             mBuffer.editRawFixed32(sizePos+4, 0);
2131         } else {
2132             // The object has no data.  Don't include it.
2133             mBuffer.rewindWriteTo(sizePos - getTagSizeFromToken(token));
2134         }
2135     }
2136 
2137     /**
2138      * Write an object that has already been flattened.
2139      *
2140      * @deprecated Use {@link #write(long, byte[])} instead.
2141      * @hide
2142      */
2143     @Deprecated
writeObject(long fieldId, @Nullable byte[] value)2144     public void writeObject(long fieldId, @Nullable byte[] value) {
2145         assertNotCompacted();
2146         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
2147 
2148         writeObjectImpl(id, value);
2149     }
2150 
writeObjectImpl(int id, byte[] value)2151     void writeObjectImpl(int id, byte[] value) {
2152         if (value != null && value.length != 0) {
2153             writeKnownLengthHeader(id, value.length);
2154             mBuffer.writeRawBuffer(value);
2155         }
2156     }
2157 
2158     /**
2159      * Write an object that has already been flattened.
2160      *
2161      * @deprecated Use {@link #write(long, byte[])} instead.
2162      * @hide
2163      */
2164     @Deprecated
writeRepeatedObject(long fieldId, @Nullable byte[] value)2165     public void writeRepeatedObject(long fieldId, @Nullable byte[] value) {
2166         assertNotCompacted();
2167         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
2168 
2169         writeRepeatedObjectImpl(id, value);
2170     }
2171 
writeRepeatedObjectImpl(int id, byte[] value)2172     void writeRepeatedObjectImpl(int id, byte[] value) {
2173         writeKnownLengthHeader(id, value == null ? 0 : value.length);
2174         mBuffer.writeRawBuffer(value);
2175     }
2176 
2177     //
2178     // Tags
2179     //
2180 
2181     /**
2182      * Combine a fieldId (the field keys in the proto file) and the field flags.
2183      * Mostly useful for testing because the generated code contains the fieldId
2184      * constants.
2185      */
makeFieldId(int id, long fieldFlags)2186     public static long makeFieldId(int id, long fieldFlags) {
2187         return fieldFlags | (((long)id) & 0x0ffffffffL);
2188     }
2189 
2190     /**
2191      * Validates that the fieldId provided is of the type and count from expectedType.
2192      *
2193      * <p>The type must match exactly to pass this check.
2194      *
2195      * <p>The count must match according to this truth table to pass the check:
2196      *
2197      *                  expectedFlags
2198      *                  UNKNOWN     SINGLE      REPEATED    PACKED
2199      *    fieldId
2200      *    UNKNOWN       true        false       false       false
2201      *    SINGLE        x           true        false       false
2202      *    REPEATED      x           false       true        false
2203      *    PACKED        x           false       true        true
2204      *
2205      * @throws {@link IllegalArgumentException} if it is not.
2206      *
2207      * @return The raw ID of that field.
2208      */
checkFieldId(long fieldId, long expectedFlags)2209     public static int checkFieldId(long fieldId, long expectedFlags) {
2210         final long fieldCount = fieldId & FIELD_COUNT_MASK;
2211         final long fieldType = fieldId & FIELD_TYPE_MASK;
2212         final long expectedCount = expectedFlags & FIELD_COUNT_MASK;
2213         final long expectedType = expectedFlags & FIELD_TYPE_MASK;
2214         if (((int)fieldId) == 0) {
2215             throw new IllegalArgumentException("Invalid proto field " + (int)fieldId
2216                     + " fieldId=" + Long.toHexString(fieldId));
2217         }
2218         if (fieldType != expectedType
2219                 || !((fieldCount == expectedCount)
2220                     || (fieldCount == FIELD_COUNT_PACKED
2221                         && expectedCount == FIELD_COUNT_REPEATED))) {
2222             final String countString = getFieldCountString(fieldCount);
2223             final String typeString = getFieldTypeString(fieldType);
2224             if (typeString != null && countString != null) {
2225                 final StringBuilder sb = new StringBuilder();
2226                 if (expectedType == FIELD_TYPE_MESSAGE) {
2227                     sb.append("start");
2228                 } else {
2229                     sb.append("write");
2230                 }
2231                 sb.append(getFieldCountString(expectedCount));
2232                 sb.append(getFieldTypeString(expectedType));
2233                 sb.append(" called for field ");
2234                 sb.append((int)fieldId);
2235                 sb.append(" which should be used with ");
2236                 if (fieldType == FIELD_TYPE_MESSAGE) {
2237                     sb.append("start");
2238                 } else {
2239                     sb.append("write");
2240                 }
2241                 sb.append(countString);
2242                 sb.append(typeString);
2243                 if (fieldCount == FIELD_COUNT_PACKED) {
2244                     sb.append(" or writeRepeated");
2245                     sb.append(typeString);
2246                 }
2247                 sb.append('.');
2248                 throw new IllegalArgumentException(sb.toString());
2249             } else {
2250                 final StringBuilder sb = new StringBuilder();
2251                 if (expectedType == FIELD_TYPE_MESSAGE) {
2252                     sb.append("start");
2253                 } else {
2254                     sb.append("write");
2255                 }
2256                 sb.append(getFieldCountString(expectedCount));
2257                 sb.append(getFieldTypeString(expectedType));
2258                 sb.append(" called with an invalid fieldId: 0x");
2259                 sb.append(Long.toHexString(fieldId));
2260                 sb.append(". The proto field ID might be ");
2261                 sb.append((int)fieldId);
2262                 sb.append('.');
2263                 throw new IllegalArgumentException(sb.toString());
2264             }
2265         }
2266         return (int)fieldId;
2267     }
2268 
2269     /**
2270      * Return how many bytes an encoded field tag will require.
2271      */
getTagSize(int id)2272     private static int getTagSize(int id) {
2273         return EncodedBuffer.getRawVarint32Size(id << FIELD_ID_SHIFT);
2274     }
2275 
2276     /**
2277      * Write an individual field tag by hand.
2278      *
2279      * See <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
2280      * Encoding</a> for details on the structure of how tags and data are written.
2281      */
writeTag(int id, @WireType int wireType)2282     public void writeTag(int id, @WireType int wireType) {
2283         mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType);
2284     }
2285 
2286     /**
2287      * Write the header of a WIRE_TYPE_LENGTH_DELIMITED field for one where
2288      * we know the size in advance and do not need to compute and compact.
2289      */
writeKnownLengthHeader(int id, int size)2290     private void writeKnownLengthHeader(int id, int size) {
2291         // Write the tag
2292         writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
2293         // Size will be compacted later, but we know the size, so write it,
2294         // once for the rawSize and once for the encodedSize.
2295         mBuffer.writeRawFixed32(size);
2296         mBuffer.writeRawFixed32(size);
2297     }
2298 
2299     //
2300     // Getting the buffer and compaction
2301     //
2302 
2303     /**
2304      * Assert that the compact call has not already occured.
2305      *
2306      * TODO: Will change when we add the OutputStream version of ProtoOutputStream.
2307      */
assertNotCompacted()2308     private void assertNotCompacted() {
2309         if (mCompacted) {
2310             throw new IllegalArgumentException("write called after compact");
2311         }
2312     }
2313 
2314     /**
2315      * Finish the encoding of the data, and return a byte[] with
2316      * the protobuf formatted data.
2317      *
2318      * <p>After this call, do not call any of the write* functions. The
2319      * behavior is undefined.
2320      */
getBytes()2321     public @NonNull byte[] getBytes() {
2322         compactIfNecessary();
2323 
2324         return mBuffer.getBytes(mBuffer.getReadableSize());
2325     }
2326 
2327     /**
2328      * If the buffer hasn't already had the nested object size fields compacted
2329      * and turned into an actual protobuf format, then do so.
2330      */
compactIfNecessary()2331     private void compactIfNecessary() {
2332         if (!mCompacted) {
2333             if (mDepth != 0) {
2334                 throw new IllegalArgumentException("Trying to compact with " + mDepth
2335                         + " missing calls to endObject");
2336             }
2337 
2338             // The buffer must be compacted.
2339             mBuffer.startEditing();
2340             final int readableSize = mBuffer.getReadableSize();
2341 
2342             // Cache the sizes of the objects
2343             editEncodedSize(readableSize);
2344 
2345             // Re-write the buffer with the sizes as proper varints instead
2346             // of pairs of uint32s. We know this will always fit in the same
2347             // buffer because the pair of uint32s is exactly 8 bytes long, and
2348             // the single varint size will be no more than 5 bytes long.
2349             mBuffer.rewindRead();
2350             compactSizes(readableSize);
2351 
2352             // If there is any data left over that wasn't copied yet, copy it.
2353             if (mCopyBegin < readableSize) {
2354                 mBuffer.writeFromThisBuffer(mCopyBegin, readableSize - mCopyBegin);
2355             }
2356 
2357             // Set the new readableSize
2358             mBuffer.startEditing();
2359 
2360             // It's not valid to write to this object anymore. The write
2361             // pointers are off, and then some of the data would be compacted
2362             // and some not.
2363             mCompacted = true;
2364         }
2365     }
2366 
2367     /**
2368      * First compaction pass. Iterate through the data, and fill in the
2369      * nested object sizes so the next pass can compact them.
2370      */
editEncodedSize(int rawSize)2371     private int editEncodedSize(int rawSize) {
2372         int objectStart = mBuffer.getReadPos();
2373         int objectEnd = objectStart + rawSize;
2374         int encodedSize = 0;
2375         int tagPos;
2376 
2377         while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
2378             int tag = readRawTag();
2379             encodedSize += EncodedBuffer.getRawVarint32Size(tag);
2380 
2381             final int wireType = tag & WIRE_TYPE_MASK;
2382             switch (wireType) {
2383                 case WIRE_TYPE_VARINT:
2384                     encodedSize++;
2385                     while ((mBuffer.readRawByte() & 0x80) != 0) {
2386                         encodedSize++;
2387                     }
2388                     break;
2389                 case WIRE_TYPE_FIXED64:
2390                     encodedSize += 8;
2391                     mBuffer.skipRead(8);
2392                     break;
2393                 case WIRE_TYPE_LENGTH_DELIMITED: {
2394                     // This object is not of a fixed-size type.  So we need to figure
2395                     // out how big it should be.
2396                     final int childRawSize = mBuffer.readRawFixed32();
2397                     final int childEncodedSizePos = mBuffer.getReadPos();
2398                     int childEncodedSize = mBuffer.readRawFixed32();
2399                     if (childRawSize >= 0) {
2400                         // We know the size, just skip ahead.
2401                         if (childEncodedSize != childRawSize) {
2402                             throw new RuntimeException("Pre-computed size where the"
2403                                     + " precomputed size and the raw size in the buffer"
2404                                     + " don't match! childRawSize=" + childRawSize
2405                                     + " childEncodedSize=" + childEncodedSize
2406                                     + " childEncodedSizePos=" + childEncodedSizePos);
2407                         }
2408                         mBuffer.skipRead(childRawSize);
2409                     } else {
2410                         // We need to compute the size.  Recurse.
2411                         childEncodedSize = editEncodedSize(-childRawSize);
2412                         mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
2413                     }
2414                     encodedSize += EncodedBuffer.getRawVarint32Size(childEncodedSize)
2415                             + childEncodedSize;
2416                     break;
2417                 }
2418                 case WIRE_TYPE_START_GROUP:
2419                 case WIRE_TYPE_END_GROUP:
2420                     throw new RuntimeException("groups not supported at index " + tagPos);
2421                 case WIRE_TYPE_FIXED32:
2422                     encodedSize += 4;
2423                     mBuffer.skipRead(4);
2424                     break;
2425                 default:
2426                     throw new ProtoParseException("editEncodedSize Bad tag tag=0x"
2427                             + Integer.toHexString(tag) + " wireType=" + wireType
2428                             + " -- " + mBuffer.getDebugString());
2429             }
2430         }
2431 
2432         return encodedSize;
2433     }
2434 
2435     /**
2436      * Second compaction pass.  Iterate through the data, and copy the data
2437      * forward in the buffer, converting the pairs of uint32s into a single
2438      * unsigned varint of the size.
2439      */
compactSizes(int rawSize)2440     private void compactSizes(int rawSize) {
2441         int objectStart = mBuffer.getReadPos();
2442         int objectEnd = objectStart + rawSize;
2443         int tagPos;
2444         while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
2445             int tag = readRawTag();
2446 
2447             // For all the non-length-delimited field types, just skip over them,
2448             // and we'll just System.arraycopy it later, either in the case for
2449             // WIRE_TYPE_LENGTH_DELIMITED or at the top of the stack in compactIfNecessary().
2450             final int wireType = tag & WIRE_TYPE_MASK;
2451             switch (wireType) {
2452                 case WIRE_TYPE_VARINT:
2453                     while ((mBuffer.readRawByte() & 0x80) != 0) { }
2454                     break;
2455                 case WIRE_TYPE_FIXED64:
2456                     mBuffer.skipRead(8);
2457                     break;
2458                 case WIRE_TYPE_LENGTH_DELIMITED: {
2459                     // Copy everything up to now, including the tag for this field.
2460                     mBuffer.writeFromThisBuffer(mCopyBegin, mBuffer.getReadPos() - mCopyBegin);
2461                     // Write the new size.
2462                     final int childRawSize = mBuffer.readRawFixed32();
2463                     final int childEncodedSize = mBuffer.readRawFixed32();
2464                     mBuffer.writeRawVarint32(childEncodedSize);
2465                     // Next time, start copying from here.
2466                     mCopyBegin = mBuffer.getReadPos();
2467                     if (childRawSize >= 0) {
2468                         // This is raw data, not an object. Skip ahead by the size.
2469                         // Recurse into the child
2470                         mBuffer.skipRead(childEncodedSize);
2471                     } else {
2472                         compactSizes(-childRawSize);
2473                     }
2474                     break;
2475                     // TODO: What does regular proto do if the object would be 0 size
2476                     // (e.g. if it is all default values).
2477                 }
2478                 case WIRE_TYPE_START_GROUP:
2479                 case WIRE_TYPE_END_GROUP:
2480                     throw new RuntimeException("groups not supported at index " + tagPos);
2481                 case WIRE_TYPE_FIXED32:
2482                     mBuffer.skipRead(4);
2483                     break;
2484                 default:
2485                     throw new ProtoParseException("compactSizes Bad tag tag=0x"
2486                             + Integer.toHexString(tag) + " wireType=" + wireType
2487                             + " -- " + mBuffer.getDebugString());
2488             }
2489         }
2490     }
2491 
2492     /**
2493      * Write remaining data to the output stream.  If there is no output stream,
2494      * this function does nothing. Any currently open objects (i.e. ones that
2495      * have not had {@link #end(long)} called for them will not be written).  Whether this
2496      * writes objects that are closed if there are remaining open objects is
2497      * undefined (current implementation does not write it, future ones will).
2498      * For now, can either call {@link #getBytes()} or {@link #flush()}, but not both.
2499      */
flush()2500     public void flush() {
2501         if (mStream == null) {
2502             return;
2503         }
2504         if (mDepth != 0) {
2505             // TODO: The compacting code isn't ready yet to compact unless we're done.
2506             // TODO: Fix that.
2507             return;
2508         }
2509         if (mCompacted) {
2510             // If we're compacted, we already wrote it finished.
2511             return;
2512         }
2513         compactIfNecessary();
2514         final byte[] data = mBuffer.getBytes(mBuffer.getReadableSize());
2515         try {
2516             mStream.write(data);
2517             mStream.flush();
2518         } catch (IOException ex) {
2519             throw new RuntimeException("Error flushing proto to stream", ex);
2520         }
2521     }
2522 
2523     /**
2524      * Read a raw tag from the buffer.
2525      */
readRawTag()2526     private int readRawTag() {
2527         if (mBuffer.getReadPos() == mBuffer.getReadableSize()) {
2528             return 0;
2529         }
2530         return (int)mBuffer.readRawUnsigned();
2531     }
2532 
2533     /**
2534      * Dump debugging data about the buffers with the given log tag.
2535      */
dump(@onNull String tag)2536     public void dump(@NonNull String tag) {
2537         Log.d(tag, mBuffer.getDebugString());
2538         mBuffer.dumpBuffers(tag);
2539     }
2540 }
2541