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