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