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