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