Home | History | Annotate | Download | only in proto
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util.proto;
     18 
     19 import android.annotation.TestApi;
     20 import android.util.Log;
     21 
     22 import java.io.FileDescriptor;
     23 import java.io.FileOutputStream;
     24 import java.io.IOException;
     25 import java.io.OutputStream;
     26 import java.io.UnsupportedEncodingException;
     27 
     28 /**
     29  * Class to write to a protobuf stream.
     30  *
     31  * Each write method takes an ID code from the protoc generated classes
     32  * and the value to write.  To make a nested object, call 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
    103 public final class ProtoOutputStream {
    104     public static final String TAG = "ProtoOutputStream";
    105 
    106     public static final int FIELD_ID_SHIFT = 3;
    107     public static final int WIRE_TYPE_MASK = (1<<FIELD_ID_SHIFT)-1;
    108     public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
    109 
    110     public static final int WIRE_TYPE_VARINT = 0;
    111     public static final int WIRE_TYPE_FIXED64 = 1;
    112     public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
    113     public static final int WIRE_TYPE_START_GROUP = 3;
    114     public static final int WIRE_TYPE_END_GROUP = 4;
    115     public static final int WIRE_TYPE_FIXED32 = 5;
    116 
    117     /**
    118      * Position of the field type in a (long) fieldId.
    119      */
    120     public static final int FIELD_TYPE_SHIFT = 32;
    121 
    122     /**
    123      * Mask for the field types stored in a fieldId.  Leaves a whole
    124      * byte for future expansion, even though there are currently only 17 types.
    125      */
    126     public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
    127 
    128     public static final long FIELD_TYPE_UNKNOWN = 0;
    129 
    130     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