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