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