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