ProtoOutputStream.java revision fb9f736a3c6c2e1c91c69b1abc0456b54215e8ef
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 public void writeDouble(long fieldId, double val) { 933 assertNotCompacted(); 934 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE); 935 936 writeDoubleImpl(id, val); 937 } 938 939 private void writeDoubleImpl(int id, double val) { 940 if (val != 0) { 941 writeTag(id, WIRE_TYPE_FIXED64); 942 mBuffer.writeRawFixed64(Double.doubleToLongBits(val)); 943 } 944 } 945 946 /** 947 * Write a single repeated proto "double" type field value. 948 */ 949 public void writeRepeatedDouble(long fieldId, double val) { 950 assertNotCompacted(); 951 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_DOUBLE); 952 953 writeRepeatedDoubleImpl(id, val); 954 } 955 956 private void writeRepeatedDoubleImpl(int id, double val) { 957 writeTag(id, WIRE_TYPE_FIXED64); 958 mBuffer.writeRawFixed64(Double.doubleToLongBits(val)); 959 } 960 961 /** 962 * Write a list of packed proto "double" type field values. 963 */ 964 public void writePackedDouble(long fieldId, double[] val) { 965 assertNotCompacted(); 966 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE); 967 968 final int N = val != null ? val.length : 0; 969 if (N > 0) { 970 writeKnownLengthHeader(id, N * 8); 971 for (int i=0; i<N; i++) { 972 mBuffer.writeRawFixed64(Double.doubleToLongBits(val[i])); 973 } 974 } 975 } 976 977 // 978 // proto3 type: float 979 // java type: float 980 // encoding: fixed32 981 // wire type: WIRE_TYPE_FIXED32 982 // 983 984 /** 985 * Write a single proto "float" type field value. 986 */ 987 public void writeFloat(long fieldId, float val) { 988 assertNotCompacted(); 989 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT); 990 991 writeFloatImpl(id, val); 992 } 993 994 private void writeFloatImpl(int id, float val) { 995 if (val != 0) { 996 writeTag(id, WIRE_TYPE_FIXED32); 997 mBuffer.writeRawFixed32(Float.floatToIntBits(val)); 998 } 999 } 1000 1001 /** 1002 * Write a single repeated proto "float" type field value. 1003 */ 1004 public void writeRepeatedFloat(long fieldId, float val) { 1005 assertNotCompacted(); 1006 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FLOAT); 1007 1008 writeRepeatedFloatImpl(id, val); 1009 } 1010 1011 private void writeRepeatedFloatImpl(int id, float val) { 1012 writeTag(id, WIRE_TYPE_FIXED32); 1013 mBuffer.writeRawFixed32(Float.floatToIntBits(val)); 1014 } 1015 1016 /** 1017 * Write a list of packed proto "float" type field value. 1018 */ 1019 public void writePackedFloat(long fieldId, float[] val) { 1020 assertNotCompacted(); 1021 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT); 1022 1023 final int N = val != null ? val.length : 0; 1024 if (N > 0) { 1025 writeKnownLengthHeader(id, N * 4); 1026 for (int i=0; i<N; i++) { 1027 mBuffer.writeRawFixed32(Float.floatToIntBits(val[i])); 1028 } 1029 } 1030 } 1031 1032 // 1033 // proto3 type: int32 1034 // java type: int 1035 // signed/unsigned: signed 1036 // encoding: varint 1037 // wire type: WIRE_TYPE_VARINT 1038 // 1039 1040 /** 1041 * Writes a java int as an usigned varint. 1042 * 1043 * The unadorned int32 type in protobuf is unfortunate because it 1044 * is stored in memory as a signed value, but encodes as unsigned 1045 * varints, which are formally always longs. So here, we encode 1046 * negative values as 64 bits, which will get the sign-extension, 1047 * and positive values as 32 bits, which saves a marginal amount 1048 * of work in that it processes ints instead of longs. 1049 */ 1050 private void writeUnsignedVarintFromSignedInt(int val) { 1051 if (val >= 0) { 1052 mBuffer.writeRawVarint32(val); 1053 } else { 1054 mBuffer.writeRawVarint64(val); 1055 } 1056 } 1057 1058 /** 1059 * Write a single proto "int32" type field value. 1060 * 1061 * Note that these are stored in memory as signed values and written as unsigned 1062 * varints, which if negative, are 10 bytes long. If you know the data is likely 1063 * to be negative, use "sint32". 1064 */ 1065 public void writeInt32(long fieldId, int val) { 1066 assertNotCompacted(); 1067 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT32); 1068 1069 writeInt32Impl(id, val); 1070 } 1071 1072 private void writeInt32Impl(int id, int val) { 1073 if (val != 0) { 1074 writeTag(id, WIRE_TYPE_VARINT); 1075 writeUnsignedVarintFromSignedInt(val); 1076 } 1077 } 1078 1079 /** 1080 * Write a single repeated proto "int32" type field value. 1081 * 1082 * Note that these are stored in memory as signed values and written as unsigned 1083 * varints, which if negative, are 10 bytes long. If you know the data is likely 1084 * to be negative, use "sint32". 1085 */ 1086 public void writeRepeatedInt32(long fieldId, int val) { 1087 assertNotCompacted(); 1088 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT32); 1089 1090 writeRepeatedInt32Impl(id, val); 1091 } 1092 1093 private void writeRepeatedInt32Impl(int id, int val) { 1094 writeTag(id, WIRE_TYPE_VARINT); 1095 writeUnsignedVarintFromSignedInt(val); 1096 } 1097 1098 /** 1099 * Write a list of packed proto "int32" type field value. 1100 * 1101 * Note that these are stored in memory as signed values and written as unsigned 1102 * varints, which if negative, are 10 bytes long. If you know the data is likely 1103 * to be negative, use "sint32". 1104 */ 1105 public void writePackedInt32(long fieldId, int[] val) { 1106 assertNotCompacted(); 1107 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32); 1108 1109 final int N = val != null ? val.length : 0; 1110 if (N > 0) { 1111 int size = 0; 1112 for (int i=0; i<N; i++) { 1113 final int v = val[i]; 1114 size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10; 1115 } 1116 writeKnownLengthHeader(id, size); 1117 for (int i=0; i<N; i++) { 1118 writeUnsignedVarintFromSignedInt(val[i]); 1119 } 1120 } 1121 } 1122 1123 // 1124 // proto3 type: int64 1125 // java type: int 1126 // signed/unsigned: signed 1127 // encoding: varint 1128 // wire type: WIRE_TYPE_VARINT 1129 // 1130 1131 /** 1132 * Write a single proto "int64" type field value. 1133 */ 1134 public void writeInt64(long fieldId, long val) { 1135 assertNotCompacted(); 1136 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT64); 1137 1138 writeInt64Impl(id, val); 1139 } 1140 1141 private void writeInt64Impl(int id, long val) { 1142 if (val != 0) { 1143 writeTag(id, WIRE_TYPE_VARINT); 1144 mBuffer.writeRawVarint64(val); 1145 } 1146 } 1147 1148 /** 1149 * Write a single repeated proto "int64" type field value. 1150 */ 1151 public void writeRepeatedInt64(long fieldId, long val) { 1152 assertNotCompacted(); 1153 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT64); 1154 1155 writeRepeatedInt64Impl(id, val); 1156 } 1157 1158 private void writeRepeatedInt64Impl(int id, long val) { 1159 writeTag(id, WIRE_TYPE_VARINT); 1160 mBuffer.writeRawVarint64(val); 1161 } 1162 1163 /** 1164 * Write a list of packed proto "int64" type field value. 1165 */ 1166 public void writePackedInt64(long fieldId, long[] val) { 1167 assertNotCompacted(); 1168 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64); 1169 1170 final int N = val != null ? val.length : 0; 1171 if (N > 0) { 1172 int size = 0; 1173 for (int i=0; i<N; i++) { 1174 size += EncodedBuffer.getRawVarint64Size(val[i]); 1175 } 1176 writeKnownLengthHeader(id, size); 1177 for (int i=0; i<N; i++) { 1178 mBuffer.writeRawVarint64(val[i]); 1179 } 1180 } 1181 } 1182 1183 // 1184 // proto3 type: uint32 1185 // java type: int 1186 // signed/unsigned: unsigned 1187 // encoding: varint 1188 // wire type: WIRE_TYPE_VARINT 1189 // 1190 1191 /** 1192 * Write a single proto "uint32" type field value. 1193 */ 1194 public void writeUInt32(long fieldId, int val) { 1195 assertNotCompacted(); 1196 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32); 1197 1198 writeUInt32Impl(id, val); 1199 } 1200 1201 private void writeUInt32Impl(int id, int val) { 1202 if (val != 0) { 1203 writeTag(id, WIRE_TYPE_VARINT); 1204 mBuffer.writeRawVarint32(val); 1205 } 1206 } 1207 1208 /** 1209 * Write a single repeated proto "uint32" type field value. 1210 */ 1211 public void writeRepeatedUInt32(long fieldId, int val) { 1212 assertNotCompacted(); 1213 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT32); 1214 1215 writeRepeatedUInt32Impl(id, val); 1216 } 1217 1218 private void writeRepeatedUInt32Impl(int id, int val) { 1219 writeTag(id, WIRE_TYPE_VARINT); 1220 mBuffer.writeRawVarint32(val); 1221 } 1222 1223 /** 1224 * Write a list of packed proto "uint32" type field value. 1225 */ 1226 public void writePackedUInt32(long fieldId, int[] val) { 1227 assertNotCompacted(); 1228 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32); 1229 1230 final int N = val != null ? val.length : 0; 1231 if (N > 0) { 1232 int size = 0; 1233 for (int i=0; i<N; i++) { 1234 size += EncodedBuffer.getRawVarint32Size(val[i]); 1235 } 1236 writeKnownLengthHeader(id, size); 1237 for (int i=0; i<N; i++) { 1238 mBuffer.writeRawVarint32(val[i]); 1239 } 1240 } 1241 } 1242 1243 // 1244 // proto3 type: uint64 1245 // java type: int 1246 // signed/unsigned: unsigned 1247 // encoding: varint 1248 // wire type: WIRE_TYPE_VARINT 1249 // 1250 1251 /** 1252 * Write a single proto "uint64" type field value. 1253 */ 1254 public void writeUInt64(long fieldId, long val) { 1255 assertNotCompacted(); 1256 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64); 1257 1258 writeUInt64Impl(id, val); 1259 } 1260 1261 private void writeUInt64Impl(int id, long val) { 1262 if (val != 0) { 1263 writeTag(id, WIRE_TYPE_VARINT); 1264 mBuffer.writeRawVarint64(val); 1265 } 1266 } 1267 1268 /** 1269 * Write a single proto "uint64" type field value. 1270 */ 1271 public void writeRepeatedUInt64(long fieldId, long val) { 1272 assertNotCompacted(); 1273 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT64); 1274 1275 writeRepeatedUInt64Impl(id, val); 1276 } 1277 1278 private void writeRepeatedUInt64Impl(int id, long val) { 1279 writeTag(id, WIRE_TYPE_VARINT); 1280 mBuffer.writeRawVarint64(val); 1281 } 1282 1283 /** 1284 * Write a single proto "uint64" type field value. 1285 */ 1286 public void writePackedUInt64(long fieldId, long[] val) { 1287 assertNotCompacted(); 1288 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64); 1289 1290 final int N = val != null ? val.length : 0; 1291 if (N > 0) { 1292 int size = 0; 1293 for (int i=0; i<N; i++) { 1294 size += EncodedBuffer.getRawVarint64Size(val[i]); 1295 } 1296 writeKnownLengthHeader(id, size); 1297 for (int i=0; i<N; i++) { 1298 mBuffer.writeRawVarint64(val[i]); 1299 } 1300 } 1301 } 1302 1303 // 1304 // proto3 type: sint32 1305 // java type: int 1306 // signed/unsigned: signed 1307 // encoding: zig-zag 1308 // wire type: WIRE_TYPE_VARINT 1309 // 1310 1311 /** 1312 * Write a single proto "sint32" type field value. 1313 */ 1314 public void writeSInt32(long fieldId, int val) { 1315 assertNotCompacted(); 1316 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32); 1317 1318 writeSInt32Impl(id, val); 1319 } 1320 1321 private void writeSInt32Impl(int id, int val) { 1322 if (val != 0) { 1323 writeTag(id, WIRE_TYPE_VARINT); 1324 mBuffer.writeRawZigZag32(val); 1325 } 1326 } 1327 1328 /** 1329 * Write a single repeated proto "sint32" type field value. 1330 */ 1331 public void writeRepeatedSInt32(long fieldId, int val) { 1332 assertNotCompacted(); 1333 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT32); 1334 1335 writeRepeatedSInt32Impl(id, val); 1336 } 1337 1338 private void writeRepeatedSInt32Impl(int id, int val) { 1339 writeTag(id, WIRE_TYPE_VARINT); 1340 mBuffer.writeRawZigZag32(val); 1341 } 1342 1343 /** 1344 * Write a list of packed proto "sint32" type field value. 1345 */ 1346 public void writePackedSInt32(long fieldId, int[] val) { 1347 assertNotCompacted(); 1348 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32); 1349 1350 final int N = val != null ? val.length : 0; 1351 if (N > 0) { 1352 int size = 0; 1353 for (int i=0; i<N; i++) { 1354 size += EncodedBuffer.getRawZigZag32Size(val[i]); 1355 } 1356 writeKnownLengthHeader(id, size); 1357 for (int i=0; i<N; i++) { 1358 mBuffer.writeRawZigZag32(val[i]); 1359 } 1360 } 1361 } 1362 1363 // 1364 // proto3 type: sint64 1365 // java type: int 1366 // signed/unsigned: signed 1367 // encoding: zig-zag 1368 // wire type: WIRE_TYPE_VARINT 1369 // 1370 1371 /** 1372 * Write a single proto "sint64" type field value. 1373 */ 1374 public void writeSInt64(long fieldId, long val) { 1375 assertNotCompacted(); 1376 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64); 1377 1378 writeSInt64Impl(id, val); 1379 } 1380 1381 private void writeSInt64Impl(int id, long val) { 1382 if (val != 0) { 1383 writeTag(id, WIRE_TYPE_VARINT); 1384 mBuffer.writeRawZigZag64(val); 1385 } 1386 } 1387 1388 /** 1389 * Write a single repeated proto "sint64" type field value. 1390 */ 1391 public void writeRepeatedSInt64(long fieldId, long val) { 1392 assertNotCompacted(); 1393 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT64); 1394 1395 writeRepeatedSInt64Impl(id, val); 1396 } 1397 1398 private void writeRepeatedSInt64Impl(int id, long val) { 1399 writeTag(id, WIRE_TYPE_VARINT); 1400 mBuffer.writeRawZigZag64(val); 1401 } 1402 1403 /** 1404 * Write a list of packed proto "sint64" type field value. 1405 */ 1406 public void writePackedSInt64(long fieldId, long[] val) { 1407 assertNotCompacted(); 1408 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64); 1409 1410 final int N = val != null ? val.length : 0; 1411 if (N > 0) { 1412 int size = 0; 1413 for (int i=0; i<N; i++) { 1414 size += EncodedBuffer.getRawZigZag64Size(val[i]); 1415 } 1416 writeKnownLengthHeader(id, size); 1417 for (int i=0; i<N; i++) { 1418 mBuffer.writeRawZigZag64(val[i]); 1419 } 1420 } 1421 } 1422 1423 // 1424 // proto3 type: fixed32 1425 // java type: int 1426 // encoding: little endian 1427 // wire type: WIRE_TYPE_FIXED32 1428 // 1429 1430 /** 1431 * Write a single proto "fixed32" type field value. 1432 */ 1433 public void writeFixed32(long fieldId, int val) { 1434 assertNotCompacted(); 1435 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32); 1436 1437 writeFixed32Impl(id, val); 1438 } 1439 1440 private void writeFixed32Impl(int id, int val) { 1441 if (val != 0) { 1442 writeTag(id, WIRE_TYPE_FIXED32); 1443 mBuffer.writeRawFixed32(val); 1444 } 1445 } 1446 1447 /** 1448 * Write a single repeated proto "fixed32" type field value. 1449 */ 1450 public void writeRepeatedFixed32(long fieldId, int val) { 1451 assertNotCompacted(); 1452 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED32); 1453 1454 writeRepeatedFixed32Impl(id, val); 1455 } 1456 1457 private void writeRepeatedFixed32Impl(int id, int val) { 1458 writeTag(id, WIRE_TYPE_FIXED32); 1459 mBuffer.writeRawFixed32(val); 1460 } 1461 1462 /** 1463 * Write a list of packed proto "fixed32" type field value. 1464 */ 1465 public void writePackedFixed32(long fieldId, int[] val) { 1466 assertNotCompacted(); 1467 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32); 1468 1469 final int N = val != null ? val.length : 0; 1470 if (N > 0) { 1471 writeKnownLengthHeader(id, N * 4); 1472 for (int i=0; i<N; i++) { 1473 mBuffer.writeRawFixed32(val[i]); 1474 } 1475 } 1476 } 1477 1478 // 1479 // proto3 type: fixed64 1480 // java type: long 1481 // encoding: fixed64 1482 // wire type: WIRE_TYPE_FIXED64 1483 // 1484 1485 /** 1486 * Write a single proto "fixed64" type field value. 1487 */ 1488 public void writeFixed64(long fieldId, long val) { 1489 assertNotCompacted(); 1490 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64); 1491 1492 writeFixed64Impl(id, val); 1493 } 1494 1495 private void writeFixed64Impl(int id, long val) { 1496 if (val != 0) { 1497 writeTag(id, WIRE_TYPE_FIXED64); 1498 mBuffer.writeRawFixed64(val); 1499 } 1500 } 1501 1502 /** 1503 * Write a single repeated proto "fixed64" type field value. 1504 */ 1505 public void writeRepeatedFixed64(long fieldId, long val) { 1506 assertNotCompacted(); 1507 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64); 1508 1509 writeRepeatedFixed64(id, val); 1510 } 1511 1512 private void writeRepeatedFixed64Impl(int id, long val) { 1513 writeTag(id, WIRE_TYPE_FIXED64); 1514 mBuffer.writeRawFixed64(val); 1515 } 1516 1517 /** 1518 * Write a list of packed proto "fixed64" type field value. 1519 */ 1520 public void writePackedFixed64(long fieldId, long[] val) { 1521 assertNotCompacted(); 1522 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64); 1523 1524 final int N = val != null ? val.length : 0; 1525 if (N > 0) { 1526 writeKnownLengthHeader(id, N * 8); 1527 for (int i=0; i<N; i++) { 1528 mBuffer.writeRawFixed64(val[i]); 1529 } 1530 } 1531 } 1532 1533 // 1534 // proto3 type: sfixed32 1535 // java type: int 1536 // encoding: little endian 1537 // wire type: WIRE_TYPE_FIXED32 1538 // 1539 /** 1540 * Write a single proto "sfixed32" type field value. 1541 */ 1542 public void writeSFixed32(long fieldId, int val) { 1543 assertNotCompacted(); 1544 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32); 1545 1546 writeSFixed32Impl(id, val); 1547 } 1548 1549 private void writeSFixed32Impl(int id, int val) { 1550 if (val != 0) { 1551 writeTag(id, WIRE_TYPE_FIXED32); 1552 mBuffer.writeRawFixed32(val); 1553 } 1554 } 1555 1556 /** 1557 * Write a single repeated proto "sfixed32" type field value. 1558 */ 1559 public void writeRepeatedSFixed32(long fieldId, int val) { 1560 assertNotCompacted(); 1561 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED32); 1562 1563 writeRepeatedSFixed32Impl(id, val); 1564 } 1565 1566 private void writeRepeatedSFixed32Impl(int id, int val) { 1567 writeTag(id, WIRE_TYPE_FIXED32); 1568 mBuffer.writeRawFixed32(val); 1569 } 1570 1571 /** 1572 * Write a list of packed proto "sfixed32" type field value. 1573 */ 1574 public void writePackedSFixed32(long fieldId, int[] val) { 1575 assertNotCompacted(); 1576 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32); 1577 1578 final int N = val != null ? val.length : 0; 1579 if (N > 0) { 1580 writeKnownLengthHeader(id, N * 4); 1581 for (int i=0; i<N; i++) { 1582 mBuffer.writeRawFixed32(val[i]); 1583 } 1584 } 1585 } 1586 1587 // 1588 // proto3 type: sfixed64 1589 // java type: long 1590 // encoding: little endian 1591 // wire type: WIRE_TYPE_FIXED64 1592 // 1593 1594 /** 1595 * Write a single proto "sfixed64" type field value. 1596 */ 1597 public void writeSFixed64(long fieldId, long val) { 1598 assertNotCompacted(); 1599 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64); 1600 1601 writeSFixed64Impl(id, val); 1602 } 1603 1604 private void writeSFixed64Impl(int id, long val) { 1605 if (val != 0) { 1606 writeTag(id, WIRE_TYPE_FIXED64); 1607 mBuffer.writeRawFixed64(val); 1608 } 1609 } 1610 1611 /** 1612 * Write a single repeated proto "sfixed64" type field value. 1613 */ 1614 public void writeRepeatedSFixed64(long fieldId, long val) { 1615 assertNotCompacted(); 1616 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64); 1617 1618 writeRepeatedSFixed64(id, val); 1619 } 1620 1621 private void writeRepeatedSFixed64Impl(int id, long val) { 1622 writeTag(id, WIRE_TYPE_FIXED64); 1623 mBuffer.writeRawFixed64(val); 1624 } 1625 1626 /** 1627 * Write a list of packed proto "sfixed64" type field value. 1628 */ 1629 public void writePackedSFixed64(long fieldId, long[] val) { 1630 assertNotCompacted(); 1631 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64); 1632 1633 final int N = val != null ? val.length : 0; 1634 if (N > 0) { 1635 writeKnownLengthHeader(id, N * 8); 1636 for (int i=0; i<N; i++) { 1637 mBuffer.writeRawFixed64(val[i]); 1638 } 1639 } 1640 } 1641 1642 // 1643 // proto3 type: bool 1644 // java type: boolean 1645 // encoding: varint 1646 // wire type: WIRE_TYPE_VARINT 1647 // 1648 1649 /** 1650 * Write a single proto "bool" type field value. 1651 */ 1652 public void writeBool(long fieldId, boolean val) { 1653 assertNotCompacted(); 1654 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL); 1655 1656 writeBoolImpl(id, val); 1657 } 1658 1659 private void writeBoolImpl(int id, boolean val) { 1660 if (val) { 1661 writeTag(id, WIRE_TYPE_VARINT); 1662 // 0 and 1 are the same as their varint counterparts 1663 mBuffer.writeRawByte((byte)1); 1664 } 1665 } 1666 1667 /** 1668 * Write a single repeated proto "bool" type field value. 1669 */ 1670 public void writeRepeatedBool(long fieldId, boolean val) { 1671 assertNotCompacted(); 1672 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL); 1673 1674 writeRepeatedBool(id, val); 1675 } 1676 1677 private void writeRepeatedBoolImpl(int id, boolean val) { 1678 writeTag(id, WIRE_TYPE_VARINT); 1679 mBuffer.writeRawByte((byte)(val ? 1 : 0)); 1680 } 1681 1682 /** 1683 * Write a list of packed proto "bool" type field value. 1684 */ 1685 public void writePackedBool(long fieldId, boolean[] val) { 1686 assertNotCompacted(); 1687 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL); 1688 1689 final int N = val != null ? val.length : 0; 1690 if (N > 0) { 1691 // Write the header 1692 writeKnownLengthHeader(id, N); 1693 1694 // Write the data 1695 for (int i=0; i<N; i++) { 1696 // 0 and 1 are the same as their varint counterparts 1697 mBuffer.writeRawByte((byte)(val[i] ? 1 : 0)); 1698 } 1699 } 1700 } 1701 1702 // 1703 // proto3 type: string 1704 // java type: String 1705 // encoding: utf-8 1706 // wire type: WIRE_TYPE_LENGTH_DELIMITED 1707 // 1708 1709 /** 1710 * Write a single proto "string" type field value. 1711 */ 1712 public void writeString(long fieldId, String val) { 1713 assertNotCompacted(); 1714 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING); 1715 1716 writeStringImpl(id, val); 1717 } 1718 1719 private void writeStringImpl(int id, String val) { 1720 if (val != null && val.length() > 0) { 1721 writeUtf8String(id, val); 1722 } 1723 } 1724 1725 /** 1726 * Write a single repeated proto "string" type field value. 1727 */ 1728 public void writeRepeatedString(long fieldId, String val) { 1729 assertNotCompacted(); 1730 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING); 1731 1732 writeRepeatedStringImpl(id, val); 1733 } 1734 1735 private void writeRepeatedStringImpl(int id, String val) { 1736 if (val == null || val.length() == 0) { 1737 writeKnownLengthHeader(id, 0); 1738 } else { 1739 writeUtf8String(id, val); 1740 } 1741 } 1742 1743 /** 1744 * Write a list of packed proto "string" type field value. 1745 */ 1746 private void writeUtf8String(int id, String val) { 1747 // TODO: Is it worth converting by hand in order to not allocate? 1748 try { 1749 final byte[] buf = val.getBytes("UTF-8"); 1750 writeKnownLengthHeader(id, buf.length); 1751 mBuffer.writeRawBuffer(buf); 1752 } catch (UnsupportedEncodingException ex) { 1753 throw new RuntimeException("not possible"); 1754 } 1755 } 1756 1757 // 1758 // proto3 type: bytes 1759 // java type: byte[] 1760 // encoding: varint 1761 // wire type: WIRE_TYPE_VARINT 1762 // 1763 1764 /** 1765 * Write a single proto "bytes" type field value. 1766 */ 1767 public void writeBytes(long fieldId, byte[] val) { 1768 assertNotCompacted(); 1769 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES); 1770 1771 writeBytesImpl(id, val); 1772 } 1773 1774 private void writeBytesImpl(int id, byte[] val) { 1775 if (val != null && val.length > 0) { 1776 writeKnownLengthHeader(id, val.length); 1777 mBuffer.writeRawBuffer(val); 1778 } 1779 } 1780 1781 /** 1782 * Write a single repeated proto "bytes" type field value. 1783 */ 1784 public void writeRepeatedBytes(long fieldId, byte[] val) { 1785 assertNotCompacted(); 1786 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES); 1787 1788 writeRepeatedBytesImpl(id, val); 1789 } 1790 1791 private void writeRepeatedBytesImpl(int id, byte[] val) { 1792 writeKnownLengthHeader(id, val == null ? 0 : val.length); 1793 mBuffer.writeRawBuffer(val); 1794 } 1795 1796 // 1797 // proto3 type: enum 1798 // java type: int 1799 // signed/unsigned: unsigned 1800 // encoding: varint 1801 // wire type: WIRE_TYPE_VARINT 1802 // 1803 1804 /** 1805 * Write a single proto enum type field value. 1806 */ 1807 public void writeEnum(long fieldId, int val) { 1808 assertNotCompacted(); 1809 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM); 1810 1811 writeEnumImpl(id, val); 1812 } 1813 1814 private void writeEnumImpl(int id, int val) { 1815 if (val != 0) { 1816 writeTag(id, WIRE_TYPE_VARINT); 1817 writeUnsignedVarintFromSignedInt(val); 1818 } 1819 } 1820 1821 /** 1822 * Write a single repeated proto enum type field value. 1823 */ 1824 public void writeRepeatedEnum(long fieldId, int val) { 1825 assertNotCompacted(); 1826 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_ENUM); 1827 1828 writeRepeatedEnumImpl(id, val); 1829 } 1830 1831 private void writeRepeatedEnumImpl(int id, int val) { 1832 writeTag(id, WIRE_TYPE_VARINT); 1833 writeUnsignedVarintFromSignedInt(val); 1834 } 1835 1836 /** 1837 * Write a list of packed proto enum type field value. 1838 */ 1839 public void writePackedEnum(long fieldId, int[] val) { 1840 assertNotCompacted(); 1841 final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM); 1842 1843 final int N = val != null ? val.length : 0; 1844 if (N > 0) { 1845 int size = 0; 1846 for (int i=0; i<N; i++) { 1847 final int v = val[i]; 1848 size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10; 1849 } 1850 writeKnownLengthHeader(id, size); 1851 for (int i=0; i<N; i++) { 1852 writeUnsignedVarintFromSignedInt(val[i]); 1853 } 1854 } 1855 } 1856 1857 // 1858 // Child objects 1859 // 1860 1861 /** 1862 * Make a token. 1863 * Bits 61-63 - tag size (So we can go backwards later if the object had not data) 1864 * - 3 bits, max value 7, max value needed 5 1865 * Bit 60 - true if the object is repeated (lets us require endObject or endRepeatedObject) 1866 * Bits 59-51 - depth (For error checking) 1867 * - 9 bits, max value 512, when checking, value is masked (if we really 1868 * are more than 512 levels deep) 1869 * Bits 32-50 - objectId (For error checking) 1870 * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap 1871 * because of the overflow, and only the tokens are compared. 1872 * Bits 0-31 - offset of the first size field in the buffer. 1873 */ 1874 // VisibleForTesting 1875 public static long makeToken(int tagSize, boolean repeated, int depth, int objectId, 1876 int sizePos) { 1877 return ((0x07L & (long)tagSize) << 61) 1878 | (repeated ? (1L << 60) : 0) 1879 | (0x01ffL & (long)depth) << 51 1880 | (0x07ffffL & (long)objectId) << 32 1881 | (0x0ffffffffL & (long)sizePos); 1882 } 1883 1884 /** 1885 * Get the encoded tag size from the token. 1886 */ 1887 public static int getTagSizeFromToken(long token) { 1888 return (int)(0x7 & (token >> 61)); 1889 } 1890 1891 /** 1892 * Get whether this is a call to startObject (false) or startRepeatedObject (true). 1893 */ 1894 public static boolean getRepeatedFromToken(long token) { 1895 return (0x1 & (token >> 60)) != 0; 1896 } 1897 1898 /** 1899 * Get the nesting depth of startObject calls from the token. 1900 */ 1901 public static int getDepthFromToken(long token) { 1902 return (int)(0x01ff & (token >> 51)); 1903 } 1904 1905 /** 1906 * Get the object ID from the token. The object ID is a serial number for the 1907 * startObject calls that have happened on this object. The values are truncated 1908 * to 9 bits, but that is sufficient for error checking. 1909 */ 1910 public static int getObjectIdFromToken(long token) { 1911 return (int)(0x07ffff & (token >> 32)); 1912 } 1913 1914 /** 1915 * Get the location of the childRawSize (the first 32 bit size field) in this object. 1916 */ 1917 public static int getSizePosFromToken(long token) { 1918 return (int)token; 1919 } 1920 1921 /** 1922 * Convert the object ID to the ordinal value -- the n-th call to startObject. 1923 * The object IDs start at -1 and count backwards, so that the value is unlikely 1924 * to alias with an actual size field that had been written. 1925 */ 1926 public static int convertObjectIdToOrdinal(int objectId) { 1927 return (-1 & 0x07ffff) - objectId; 1928 } 1929 1930 /** 1931 * Return a debugging string of a token. 1932 */ 1933 public static String token2String(long token) { 1934 if (token == 0L) { 1935 return "Token(0)"; 1936 } else { 1937 return "Token(val=0x" + Long.toHexString(token) 1938 + " depth=" + getDepthFromToken(token) 1939 + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token)) 1940 + " tagSize=" + getTagSizeFromToken(token) 1941 + " sizePos=" + getSizePosFromToken(token) 1942 + ')'; 1943 } 1944 } 1945 1946 /** 1947 * Start a child object. 1948 * 1949 * Returns a token which should be passed to endObject. Calls to endObject must be 1950 * nested properly. 1951 */ 1952 public long startObject(long fieldId) { 1953 assertNotCompacted(); 1954 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT); 1955 1956 return startObjectImpl(id, false); 1957 } 1958 1959 /** 1960 * End a child object. Pass in the token from the correspoinding startObject call. 1961 */ 1962 public void endObject(long token) { 1963 assertNotCompacted(); 1964 1965 endObjectImpl(token, false); 1966 } 1967 1968 /** 1969 * Start a repeated child object. 1970 * 1971 * Returns a token which should be passed to endObject. Calls to endObject must be 1972 * nested properly. 1973 */ 1974 public long startRepeatedObject(long fieldId) { 1975 assertNotCompacted(); 1976 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT); 1977 1978 return startObjectImpl(id, true); 1979 } 1980 1981 /** 1982 * End a child object. Pass in the token from the correspoinding startRepeatedObject call. 1983 */ 1984 public void endRepeatedObject(long token) { 1985 assertNotCompacted(); 1986 1987 endObjectImpl(token, true); 1988 } 1989 1990 /** 1991 * Common implementation of startObject and startRepeatedObject. 1992 */ 1993 private long startObjectImpl(final int id, boolean repeated) { 1994 writeTag(id, WIRE_TYPE_LENGTH_DELIMITED); 1995 final int sizePos = mBuffer.getWritePos(); 1996 mDepth++; 1997 mNextObjectId--; 1998 1999 // Write the previous token, giving us a stack of expected tokens. 2000 // After endObject returns, the first fixed32 becomeschildRawSize (set in endObject) 2001 // and the second one becomes childEncodedSize (set in editEncodedSize). 2002 mBuffer.writeRawFixed32((int)(mExpectedObjectToken >> 32)); 2003 mBuffer.writeRawFixed32((int)mExpectedObjectToken); 2004 2005 long old = mExpectedObjectToken; 2006 2007 mExpectedObjectToken = makeToken(getTagSize(id), repeated, mDepth, mNextObjectId, sizePos); 2008 return mExpectedObjectToken; 2009 } 2010 2011 /** 2012 * Common implementation of endObject and endRepeatedObject. 2013 */ 2014 private void endObjectImpl(long token, boolean repeated) { 2015 // The upper 32 bits of the token is the depth of startObject / 2016 // endObject calls. We could get aritrarily sophisticated, but 2017 // that's enough to prevent the common error of missing an 2018 // endObject somewhere. 2019 // The lower 32 bits of the token is the offset in the buffer 2020 // at which to write the size. 2021 final int depth = getDepthFromToken(token); 2022 final boolean expectedRepeated = getRepeatedFromToken(token); 2023 final int sizePos = getSizePosFromToken(token); 2024 final int childRawSize = mBuffer.getWritePos() - sizePos - 8; 2025 2026 if (repeated != expectedRepeated) { 2027 if (repeated) { 2028 throw new IllegalArgumentException("endRepeatedObject called where endObject should" 2029 + " have been"); 2030 } else { 2031 throw new IllegalArgumentException("endObject called where endRepeatedObject should" 2032 + " have been"); 2033 } 2034 } 2035 2036 // Check that we're getting the token and depth that we are expecting. 2037 if ((mDepth & 0x01ff) != depth || mExpectedObjectToken != token) { 2038 // This text of exception is united tested. That test also implicity checks 2039 // that we're tracking the objectIds and depths correctly. 2040 throw new IllegalArgumentException("Mismatched startObject/endObject calls." 2041 + " Current depth " + mDepth 2042 + " token=" + token2String(token) 2043 + " expectedToken=" + token2String(mExpectedObjectToken)); 2044 } 2045 2046 // Get the next expected token that we stashed away in the buffer. 2047 mExpectedObjectToken = (((long)mBuffer.getRawFixed32At(sizePos)) << 32) 2048 | (0x0ffffffffL & (long)mBuffer.getRawFixed32At(sizePos+4)); 2049 2050 mDepth--; 2051 if (childRawSize > 0) { 2052 mBuffer.editRawFixed32(sizePos, -childRawSize); 2053 mBuffer.editRawFixed32(sizePos+4, -1); 2054 } else if (repeated) { 2055 mBuffer.editRawFixed32(sizePos, 0); 2056 mBuffer.editRawFixed32(sizePos+4, 0); 2057 } else { 2058 // The object has no data. Don't include it. 2059 mBuffer.rewindWriteTo(sizePos - getTagSizeFromToken(token)); 2060 } 2061 } 2062 2063 /** 2064 * Write an object that has already been flattend. 2065 */ 2066 public void writeObject(long fieldId, byte[] value) { 2067 assertNotCompacted(); 2068 final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT); 2069 2070 writeObjectImpl(id, value); 2071 } 2072 2073 public void writeObjectImpl(int id, byte[] value) { 2074 if (value != null && value.length != 0) { 2075 writeKnownLengthHeader(id, value.length); 2076 mBuffer.writeRawBuffer(value); 2077 } 2078 } 2079 2080 /** 2081 * Write an object that has already been flattend. 2082 */ 2083 public void writeRepeatedObject(long fieldId, byte[] value) { 2084 assertNotCompacted(); 2085 final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT); 2086 2087 writeRepeatedObjectImpl(id, value); 2088 } 2089 2090 public void writeRepeatedObjectImpl(int id, byte[] value) { 2091 writeKnownLengthHeader(id, value == null ? 0 : value.length); 2092 mBuffer.writeRawBuffer(value); 2093 } 2094 2095 // 2096 // Tags 2097 // 2098 2099 /** 2100 * Combine a fieldId (the field keys in the proto file) and the field flags. 2101 * Mostly useful for testing because the generated code contains the fieldId 2102 * constants. 2103 */ 2104 public static long makeFieldId(int id, long fieldFlags) { 2105 return fieldFlags | (((long)id) & 0x0ffffffffL); 2106 } 2107 2108 /** 2109 * Validates that the fieldId providied is of the type and count from expectedType. 2110 * 2111 * The type must match exactly to pass this check. 2112 * 2113 * The count must match according to this truth table to pass the check: 2114 * 2115 * expectedFlags 2116 * UNKNOWN SINGLE REPEATED PACKED 2117 * fieldId 2118 * UNKNOWN true false false false 2119 * SINGLE x true false false 2120 * REPEATED x false true false 2121 * PACKED x false true true 2122 * 2123 * @throws IllegalArgumentException if it is not. 2124 * 2125 * @return The raw ID of that field. 2126 */ 2127 public static int checkFieldId(long fieldId, long expectedFlags) { 2128 final long fieldCount = fieldId & FIELD_COUNT_MASK; 2129 final long fieldType = fieldId & FIELD_TYPE_MASK; 2130 final long expectedCount = expectedFlags & FIELD_COUNT_MASK; 2131 final long expectedType = expectedFlags & FIELD_TYPE_MASK; 2132 if (((int)fieldId) == 0) { 2133 throw new IllegalArgumentException("Invalid proto field " + (int)fieldId 2134 + " fieldId=" + Long.toHexString(fieldId)); 2135 } 2136 if (fieldType != expectedType 2137 || !((fieldCount == expectedCount) 2138 || (fieldCount == FIELD_COUNT_PACKED 2139 && expectedCount == FIELD_COUNT_REPEATED))) { 2140 final String countString = getFieldCountString(fieldCount); 2141 final String typeString = getFieldTypeString(fieldType); 2142 if (typeString != null && countString != null) { 2143 final StringBuilder sb = new StringBuilder(); 2144 if (expectedType == FIELD_TYPE_OBJECT) { 2145 sb.append("start"); 2146 } else { 2147 sb.append("write"); 2148 } 2149 sb.append(getFieldCountString(expectedCount)); 2150 sb.append(getFieldTypeString(expectedType)); 2151 sb.append(" called for field "); 2152 sb.append((int)fieldId); 2153 sb.append(" which should be used with "); 2154 if (fieldType == FIELD_TYPE_OBJECT) { 2155 sb.append("start"); 2156 } else { 2157 sb.append("write"); 2158 } 2159 sb.append(countString); 2160 sb.append(typeString); 2161 if (fieldCount == FIELD_COUNT_PACKED) { 2162 sb.append(" or writeRepeated"); 2163 sb.append(typeString); 2164 } 2165 sb.append('.'); 2166 throw new IllegalArgumentException(sb.toString()); 2167 } else { 2168 final StringBuilder sb = new StringBuilder(); 2169 if (expectedType == FIELD_TYPE_OBJECT) { 2170 sb.append("start"); 2171 } else { 2172 sb.append("write"); 2173 } 2174 sb.append(getFieldCountString(expectedCount)); 2175 sb.append(getFieldTypeString(expectedType)); 2176 sb.append(" called with an invalid fieldId: 0x"); 2177 sb.append(Long.toHexString(fieldId)); 2178 sb.append(". The proto field ID might be "); 2179 sb.append((int)fieldId); 2180 sb.append('.'); 2181 throw new IllegalArgumentException(sb.toString()); 2182 } 2183 } 2184 return (int)fieldId; 2185 } 2186 2187 /** 2188 * Get the developer-usable name of a field type. 2189 */ 2190 private static String getFieldTypeString(long fieldType) { 2191 int index = ((int)((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1; 2192 if (index >= 0 && index < FIELD_TYPE_NAMES.length) { 2193 return FIELD_TYPE_NAMES[index]; 2194 } else { 2195 return null; 2196 } 2197 } 2198 2199 /** 2200 * Get the developer-usable name of a field count. 2201 */ 2202 private static String getFieldCountString(long fieldCount) { 2203 if (fieldCount == FIELD_COUNT_SINGLE) { 2204 return ""; 2205 } else if (fieldCount == FIELD_COUNT_REPEATED) { 2206 return "Repeated"; 2207 } else if (fieldCount == FIELD_COUNT_PACKED) { 2208 return "Packed"; 2209 } else { 2210 return null; 2211 } 2212 } 2213 2214 /** 2215 * Get a debug string for a fieldId. 2216 */ 2217 private String getFieldIdString(long fieldId) { 2218 final long fieldCount = fieldId & FIELD_COUNT_MASK; 2219 String countString = getFieldCountString(fieldCount); 2220 if (countString == null) { 2221 countString = "fieldCount=" + fieldCount; 2222 } 2223 2224 final long fieldType = fieldId & FIELD_TYPE_MASK; 2225 String typeString = getFieldTypeString(fieldType); 2226 if (typeString == null) { 2227 typeString = "fieldType=" + fieldType; 2228 } 2229 2230 return fieldCount + " " + typeString + " tag=" + ((int)fieldId) 2231 + " fieldId=0x" + Long.toHexString(fieldId); 2232 } 2233 2234 /** 2235 * Return how many bytes an encoded field tag will require. 2236 */ 2237 private static int getTagSize(int id) { 2238 return EncodedBuffer.getRawVarint32Size(id << FIELD_ID_SHIFT); 2239 } 2240 2241 /** 2242 * Write a field tage to the stream. 2243 */ 2244 public void writeTag(int id, int wireType) { 2245 mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType); 2246 } 2247 2248 /** 2249 * Write the header of a WIRE_TYPE_LENGTH_DELIMITED field for one where 2250 * we know the size in advance and do not need to compute and compact. 2251 */ 2252 private void writeKnownLengthHeader(int id, int size) { 2253 // Write the tag 2254 writeTag(id, WIRE_TYPE_LENGTH_DELIMITED); 2255 // Size will be compacted later, but we know the size, so write it, 2256 // once for the rawSize and once for the encodedSize. 2257 mBuffer.writeRawFixed32(size); 2258 mBuffer.writeRawFixed32(size); 2259 } 2260 2261 // 2262 // Getting the buffer and compaction 2263 // 2264 2265 /** 2266 * Assert that the compact call has not already occured. 2267 * 2268 * TODO: Will change when we add the OutputStream version of ProtoOutputStream. 2269 */ 2270 private void assertNotCompacted() { 2271 if (mCompacted) { 2272 throw new IllegalArgumentException("write called after compact"); 2273 } 2274 } 2275 2276 /** 2277 * Finish the encoding of the data, and return a byte[] with 2278 * the protobuf formatted data. 2279 * 2280 * After this call, do not call any of the write* functions. The 2281 * behavior is undefined. 2282 */ 2283 public byte[] getBytes() { 2284 compactIfNecessary(); 2285 2286 return mBuffer.getBytes(mBuffer.getReadableSize()); 2287 } 2288 2289 /** 2290 * If the buffer hasn't already had the nested object size fields compacted 2291 * and turned into an actual protobuf format, then do so. 2292 */ 2293 private void compactIfNecessary() { 2294 if (!mCompacted) { 2295 if (mDepth != 0) { 2296 throw new IllegalArgumentException("Trying to compact with " + mDepth 2297 + " missing calls to endObject"); 2298 } 2299 2300 // The buffer must be compacted. 2301 mBuffer.startEditing(); 2302 final int readableSize = mBuffer.getReadableSize(); 2303 2304 // Cache the sizes of the objects 2305 editEncodedSize(readableSize); 2306 2307 // Re-write the buffer with the sizes as proper varints instead 2308 // of pairs of uint32s. We know this will always fit in the same 2309 // buffer because the pair of uint32s is exactly 8 bytes long, and 2310 // the single varint size will be no more than 5 bytes long. 2311 mBuffer.rewindRead(); 2312 compactSizes(readableSize); 2313 2314 // If there is any data left over that wasn't copied yet, copy it. 2315 if (mCopyBegin < readableSize) { 2316 mBuffer.writeFromThisBuffer(mCopyBegin, readableSize - mCopyBegin); 2317 } 2318 2319 // Set the new readableSize 2320 mBuffer.startEditing(); 2321 2322 // It's not valid to write to this object anymore. The write 2323 // pointers are off, and then some of the data would be compacted 2324 // and some not. 2325 mCompacted = true; 2326 } 2327 } 2328 2329 /** 2330 * First compaction pass. Iterate through the data, and fill in the 2331 * nested object sizes so the next pass can compact them. 2332 */ 2333 private int editEncodedSize(int rawSize) { 2334 int objectStart = mBuffer.getReadPos(); 2335 int objectEnd = objectStart + rawSize; 2336 int encodedSize = 0; 2337 int tagPos; 2338 2339 while ((tagPos = mBuffer.getReadPos()) < objectEnd) { 2340 int tag = readRawTag(); 2341 encodedSize += EncodedBuffer.getRawVarint32Size(tag); 2342 2343 final int wireType = tag & WIRE_TYPE_MASK; 2344 switch (wireType) { 2345 case WIRE_TYPE_VARINT: 2346 encodedSize++; 2347 while ((mBuffer.readRawByte() & 0x80) != 0) { 2348 encodedSize++; 2349 } 2350 break; 2351 case WIRE_TYPE_FIXED64: 2352 encodedSize += 8; 2353 mBuffer.skipRead(8); 2354 break; 2355 case WIRE_TYPE_LENGTH_DELIMITED: { 2356 // This object is not of a fixed-size type. So we need to figure 2357 // out how big it should be. 2358 final int childRawSize = mBuffer.readRawFixed32(); 2359 final int childEncodedSizePos = mBuffer.getReadPos(); 2360 int childEncodedSize = mBuffer.readRawFixed32(); 2361 if (childRawSize >= 0) { 2362 // We know the size, just skip ahead. 2363 if (childEncodedSize != childRawSize) { 2364 throw new RuntimeException("Pre-computed size where the" 2365 + " precomputed size and the raw size in the buffer" 2366 + " don't match! childRawSize=" + childRawSize 2367 + " childEncodedSize=" + childEncodedSize 2368 + " childEncodedSizePos=" + childEncodedSizePos); 2369 } 2370 mBuffer.skipRead(childRawSize); 2371 } else { 2372 // We need to compute the size. Recurse. 2373 childEncodedSize = editEncodedSize(-childRawSize); 2374 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize); 2375 } 2376 encodedSize += EncodedBuffer.getRawVarint32Size(childEncodedSize) 2377 + childEncodedSize; 2378 break; 2379 } 2380 case WIRE_TYPE_START_GROUP: 2381 case WIRE_TYPE_END_GROUP: 2382 throw new RuntimeException("groups not supported at index " + tagPos); 2383 case WIRE_TYPE_FIXED32: 2384 encodedSize += 4; 2385 mBuffer.skipRead(4); 2386 break; 2387 default: 2388 throw new ProtoParseException("editEncodedSize Bad tag tag=0x" 2389 + Integer.toHexString(tag) + " wireType=" + wireType 2390 + " -- " + mBuffer.getDebugString()); 2391 } 2392 } 2393 2394 return encodedSize; 2395 } 2396 2397 /** 2398 * Second compaction pass. Iterate through the data, and copy the data 2399 * forward in the buffer, converting the pairs of uint32s into a single 2400 * unsigned varint of the size. 2401 */ 2402 private void compactSizes(int rawSize) { 2403 int objectStart = mBuffer.getReadPos(); 2404 int objectEnd = objectStart + rawSize; 2405 int tagPos; 2406 while ((tagPos = mBuffer.getReadPos()) < objectEnd) { 2407 int tag = readRawTag(); 2408 2409 // For all the non-length-delimited field types, just skip over them, 2410 // and we'll just System.arraycopy it later, either in the case for 2411 // WIRE_TYPE_LENGTH_DELIMITED or at the top of the stack in compactIfNecessary(). 2412 final int wireType = tag & WIRE_TYPE_MASK; 2413 switch (wireType) { 2414 case WIRE_TYPE_VARINT: 2415 while ((mBuffer.readRawByte() & 0x80) != 0) { } 2416 break; 2417 case WIRE_TYPE_FIXED64: 2418 mBuffer.skipRead(8); 2419 break; 2420 case WIRE_TYPE_LENGTH_DELIMITED: { 2421 // Copy everything up to now, including the tag for this field. 2422 mBuffer.writeFromThisBuffer(mCopyBegin, mBuffer.getReadPos() - mCopyBegin); 2423 // Write the new size. 2424 final int childRawSize = mBuffer.readRawFixed32(); 2425 final int childEncodedSize = mBuffer.readRawFixed32(); 2426 mBuffer.writeRawVarint32(childEncodedSize); 2427 // Next time, start copying from here. 2428 mCopyBegin = mBuffer.getReadPos(); 2429 if (childRawSize >= 0) { 2430 // This is raw data, not an object. Skip ahead by the size. 2431 // Recurse into the child 2432 mBuffer.skipRead(childEncodedSize); 2433 } else { 2434 compactSizes(-childRawSize); 2435 } 2436 break; 2437 // TODO: What does regular proto do if the object would be 0 size 2438 // (e.g. if it is all default values). 2439 } 2440 case WIRE_TYPE_START_GROUP: 2441 case WIRE_TYPE_END_GROUP: 2442 throw new RuntimeException("groups not supported at index " + tagPos); 2443 case WIRE_TYPE_FIXED32: 2444 mBuffer.skipRead(4); 2445 break; 2446 default: 2447 throw new ProtoParseException("compactSizes Bad tag tag=0x" 2448 + Integer.toHexString(tag) + " wireType=" + wireType 2449 + " -- " + mBuffer.getDebugString()); 2450 } 2451 } 2452 } 2453 2454 /** 2455 * Write remaining data to the output stream. If there is no output stream, 2456 * this function does nothing. Any currently open objects (i.e. ones that 2457 * have not had endObject called for them will not be written). Whether this 2458 * writes objects that are closed if there are remaining open objects is 2459 * undefined (current implementation does not write it, future ones will). 2460 * For now, can either call getBytes() or flush(), but not both. 2461 */ 2462 public void flush() { 2463 if (mStream == null) { 2464 return; 2465 } 2466 if (mDepth != 0) { 2467 // TODO: The compacting code isn't ready yet to compact unless we're done. 2468 // TODO: Fix that. 2469 return; 2470 } 2471 if (mCompacted) { 2472 // If we're compacted, we already wrote it finished. 2473 return; 2474 } 2475 compactIfNecessary(); 2476 final byte[] data = mBuffer.getBytes(mBuffer.getReadableSize()); 2477 try { 2478 mStream.write(data); 2479 mStream.flush(); 2480 } catch (IOException ex) { 2481 throw new RuntimeException("Error flushing proto to stream", ex); 2482 } 2483 } 2484 2485 /** 2486 * Read a raw tag from the buffer. 2487 */ 2488 private int readRawTag() { 2489 if (mBuffer.getReadPos() == mBuffer.getReadableSize()) { 2490 return 0; 2491 } 2492 return (int)mBuffer.readRawUnsigned(); 2493 } 2494 2495 /** 2496 * Dump debugging data about the buffers with the given log tag. 2497 */ 2498 public void dump(String tag) { 2499 Log.d(tag, mBuffer.getDebugString()); 2500 mBuffer.dumpBuffers(tag); 2501 } 2502} 2503