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