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