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