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