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