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