1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 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 com.facebook.thrift.protocol; 18 19 import com.facebook.thrift.ShortStack; 20 import com.facebook.thrift.TException; 21 import com.facebook.thrift.transport.TTransport; 22 import com.facebook.thrift.utils.StandardCharsets; 23 import java.util.Map; 24 25 /** 26 * TCompactProtocol2 is the Java implementation of the compact protocol specified in THRIFT-110. The 27 * fundamental approach to reducing the overhead of structures is a) use variable-length integers 28 * all over the place and b) make use of unused bits wherever possible. Your savings will obviously 29 * vary based on the specific makeup of your structs, but in general, the more fields, nested 30 * structures, short strings and collections, and low-value i32 and i64 fields you have, the more 31 * benefit you'll see. 32 */ 33 public class TCompactProtocol extends TProtocol { 34 35 private static final long NO_LENGTH_LIMIT = -1; 36 37 private static final TStruct ANONYMOUS_STRUCT = new TStruct(""); 38 private static final TField TSTOP = new TField("", TType.STOP, (short) 0); 39 40 private static final byte[] ttypeToCompactType = new byte[20]; 41 42 static { 43 ttypeToCompactType[TType.STOP] = TType.STOP; 44 ttypeToCompactType[TType.BOOL] = Types.BOOLEAN_TRUE; 45 ttypeToCompactType[TType.BYTE] = Types.BYTE; 46 ttypeToCompactType[TType.I16] = Types.I16; 47 ttypeToCompactType[TType.I32] = Types.I32; 48 ttypeToCompactType[TType.I64] = Types.I64; 49 ttypeToCompactType[TType.DOUBLE] = Types.DOUBLE; 50 ttypeToCompactType[TType.STRING] = Types.BINARY; 51 ttypeToCompactType[TType.LIST] = Types.LIST; 52 ttypeToCompactType[TType.SET] = Types.SET; 53 ttypeToCompactType[TType.MAP] = Types.MAP; 54 ttypeToCompactType[TType.STRUCT] = Types.STRUCT; 55 ttypeToCompactType[TType.FLOAT] = Types.FLOAT; 56 } 57 58 /** TProtocolFactory that produces TCompactProtocols. */ 59 @SuppressWarnings("serial") 60 public static class Factory implements TProtocolFactory { 61 private final long stringLengthLimit_; 62 private final long containerLengthLimit_; 63 Factory()64 public Factory() { 65 this(NO_LENGTH_LIMIT, NO_LENGTH_LIMIT); 66 } 67 Factory(long stringLengthLimit)68 public Factory(long stringLengthLimit) { 69 this(stringLengthLimit, NO_LENGTH_LIMIT); 70 } 71 Factory(long stringLengthLimit, long containerLengthLimit)72 public Factory(long stringLengthLimit, long containerLengthLimit) { 73 this.containerLengthLimit_ = containerLengthLimit; 74 this.stringLengthLimit_ = stringLengthLimit; 75 } 76 getProtocol(TTransport trans)77 public TProtocol getProtocol(TTransport trans) { 78 return new TCompactProtocol(trans, stringLengthLimit_, containerLengthLimit_); 79 } 80 } 81 82 public static final byte PROTOCOL_ID = (byte) 0x82; 83 public static final int TYPE_SHIFT_AMOUNT = 5; 84 private static final byte VERSION = 2; 85 private static final byte VERSION_LOW = 1; 86 private static final byte VERSION_DOUBLE_BE = 2; 87 private static final byte VERSION_MASK = 0x1f; // 0001 1111 88 private static final byte TYPE_MASK = (byte) 0xE0; // 1110 0000 89 private static final byte TYPE_BITS = 0b0000_0111; 90 91 /** All of the on-wire type codes. */ 92 private static class Types { 93 public static final byte BOOLEAN_TRUE = 0x01; 94 public static final byte BOOLEAN_FALSE = 0x02; 95 public static final byte BYTE = 0x03; 96 public static final byte I16 = 0x04; 97 public static final byte I32 = 0x05; 98 public static final byte I64 = 0x06; 99 public static final byte DOUBLE = 0x07; 100 public static final byte BINARY = 0x08; 101 public static final byte LIST = 0x09; 102 public static final byte SET = 0x0A; 103 public static final byte MAP = 0x0B; 104 public static final byte STRUCT = 0x0C; 105 public static final byte FLOAT = 0x0D; 106 } 107 108 /** 109 * Used to keep track of the last field for the current and previous structs, so we can do the 110 * delta stuff. 111 */ 112 private ShortStack lastField_ = new ShortStack(15); 113 114 private short lastFieldId_ = 0; 115 116 private byte version_ = VERSION; 117 118 /** 119 * If we encounter a boolean field begin, save the TField here so it can have the value 120 * incorporated. 121 */ 122 private TField booleanField_ = null; 123 124 /** 125 * If we read a field header, and it's a boolean field, save the boolean value here so that 126 * readBool can use it. 127 */ 128 private Boolean boolValue_ = null; 129 130 /** 131 * The maximum number of bytes to read from the transport for variable-length fields (such as 132 * strings or binary) or {@link #NO_LENGTH_LIMIT} for unlimited. 133 */ 134 private final long stringLengthLimit_; 135 136 /** 137 * The maximum number of elements to read from the network for containers (maps, sets, lists), or 138 * {@link #NO_LENGTH_LIMIT} for unlimited. 139 */ 140 private final long containerLengthLimit_; 141 142 /** Temporary buffer to avoid allocations */ 143 private final byte[] buffer = new byte[10]; 144 145 /** 146 * Create a TCompactProtocol. 147 * 148 * @param transport the TTransport object to read from or write to. 149 * @param stringLengthLimit the maximum number of bytes to read for variable-length fields. If the 150 * value is <= 0, then the check is disable. 151 * @param containerLengthLimit the maximum number of elements to read for containers. If the value 152 * is <= 0, then the check is disable. 153 */ TCompactProtocol(TTransport transport, long stringLengthLimit, long containerLengthLimit)154 public TCompactProtocol(TTransport transport, long stringLengthLimit, long containerLengthLimit) { 155 super(transport); 156 this.stringLengthLimit_ = stringLengthLimit; 157 this.containerLengthLimit_ = containerLengthLimit; 158 } 159 160 /** 161 * Create a TCompactProtocol. 162 * 163 * @param transport the TTransport object to read from or write to. 164 */ TCompactProtocol(TTransport transport)165 public TCompactProtocol(TTransport transport) { 166 this(transport, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT); 167 } 168 169 @Override reset()170 public void reset() { 171 lastField_.clear(); 172 lastFieldId_ = 0; 173 } 174 175 // 176 // Public Writing methods. 177 // 178 179 /** 180 * Write a message header to the wire. Compact Protocol messages contain the protocol version so 181 * we can migrate forwards in the future if need be. 182 */ 183 @Override writeMessageBegin(TMessage message)184 public void writeMessageBegin(TMessage message) throws TException { 185 writeByteDirect(PROTOCOL_ID); 186 writeByteDirect((VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)); 187 writeVarint32(message.seqid); 188 writeString(message.name); 189 } 190 191 /** 192 * Write a struct begin. This doesn't actually put anything on the wire. We use it as an 193 * opportunity to put special placeholder markers on the field stack so we can get the field id 194 * deltas correct. 195 */ 196 @Override writeStructBegin(TStruct struct)197 public void writeStructBegin(TStruct struct) throws TException { 198 lastField_.push(lastFieldId_); 199 lastFieldId_ = 0; 200 } 201 202 /** 203 * Write a struct end. This doesn't actually put anything on the wire. We use this as an 204 * opportunity to pop the last field from the current struct off of the field stack. 205 */ 206 @Override writeStructEnd()207 public void writeStructEnd() throws TException { 208 lastFieldId_ = lastField_.pop(); 209 } 210 211 /** 212 * Write a field header containing the field id and field type. If the difference between the 213 * current field id and the last one is small (< 15), then the field id will be encoded in the 4 214 * MSB as a delta. Otherwise, the field id will follow the type header as a zigzag varint. 215 */ 216 @Override writeFieldBegin(TField field)217 public void writeFieldBegin(TField field) throws TException { 218 if (field.type == TType.BOOL) { 219 // we want to possibly include the value, so we'll wait. 220 booleanField_ = field; 221 } else { 222 writeFieldBeginInternal(field, (byte) -1); 223 } 224 } 225 226 /** 227 * The workhorse of writeFieldBegin. It has the option of doing a 'type override' of the type 228 * header. This is used specifically in the boolean field case. 229 */ writeFieldBeginInternal(TField field, byte typeOverride)230 private void writeFieldBeginInternal(TField field, byte typeOverride) throws TException { 231 // short lastField = lastField_.pop(); 232 233 // if there's a type override, use that. 234 byte typeToWrite = typeOverride == -1 ? getCompactType(field.type) : typeOverride; 235 236 // check if we can use delta encoding for the field id 237 if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15) { 238 // write them together 239 writeByteDirect((field.id - lastFieldId_) << 4 | typeToWrite); 240 } else { 241 // write them separate 242 writeByteDirect(typeToWrite); 243 writeI16(field.id); 244 } 245 246 lastFieldId_ = field.id; 247 // lastField_.push(field.id); 248 } 249 250 /** Write the STOP symbol so we know there are no more fields in this struct. */ 251 @Override writeFieldStop()252 public void writeFieldStop() throws TException { 253 writeByteDirect(TType.STOP); 254 } 255 256 /** 257 * Write a map header. If the map is empty, omit the key and value type headers, as we don't need 258 * any additional information to skip it. 259 */ 260 @Override writeMapBegin(TMap map)261 public void writeMapBegin(TMap map) throws TException { 262 if (map.size == 0) { 263 writeByteDirect(0); 264 } else { 265 writeVarint32(map.size); 266 writeByteDirect(getCompactType(map.keyType) << 4 | getCompactType(map.valueType)); 267 } 268 } 269 270 /** Write a list header. */ 271 @Override writeListBegin(TList list)272 public void writeListBegin(TList list) throws TException { 273 writeCollectionBegin(list.elemType, list.size); 274 } 275 276 /** Write a set header. */ 277 @Override writeSetBegin(TSet set)278 public void writeSetBegin(TSet set) throws TException { 279 writeCollectionBegin(set.elemType, set.size); 280 } 281 282 /** 283 * Write a boolean value. Potentially, this could be a boolean field, in which case the field 284 * header info isn't written yet. If so, decide what the right type header is for the value and 285 * then write the field header. Otherwise, write a single byte. 286 */ 287 @Override writeBool(boolean b)288 public void writeBool(boolean b) throws TException { 289 if (booleanField_ != null) { 290 // we haven't written the field header yet 291 writeFieldBeginInternal(booleanField_, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); 292 booleanField_ = null; 293 } else { 294 // we're not part of a field, so just write the value. 295 writeByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); 296 } 297 } 298 299 /** Write a byte. Nothing to see here! */ 300 @Override writeByte(byte b)301 public void writeByte(byte b) throws TException { 302 writeByteDirect(b); 303 } 304 305 /** Write an I16 as a zigzag varint. */ 306 @Override writeI16(short i16)307 public void writeI16(short i16) throws TException { 308 writeVarint32(intToZigZag(i16)); 309 } 310 311 /** Write an i32 as a zigzag varint. */ 312 @Override writeI32(int i32)313 public void writeI32(int i32) throws TException { 314 writeVarint32(intToZigZag(i32)); 315 } 316 317 /** Write an i64 as a zigzag varint. */ 318 @Override writeI64(long i64)319 public void writeI64(long i64) throws TException { 320 writeVarint64(longToZigzag(i64)); 321 } 322 323 /** Write a double to the wire as 8 bytes. */ 324 @Override writeDouble(double dub)325 public void writeDouble(double dub) throws TException { 326 fixedLongToBytes(Double.doubleToLongBits(dub), buffer, 0); 327 trans_.write(buffer, 0, 8); 328 } 329 330 /** Write a float to the wire as 4 bytes. */ 331 @Override writeFloat(float flt)332 public void writeFloat(float flt) throws TException { 333 fixedIntToBytes(Float.floatToIntBits(flt), buffer, 0); 334 trans_.write(buffer, 0, 4); 335 } 336 337 /** Write a string to the wire with a varint size preceding. */ 338 @Override writeString(String str)339 public void writeString(String str) throws TException { 340 byte[] bytes = str.getBytes(StandardCharsets.UTF_8); 341 writeBinary(bytes, 0, bytes.length); 342 } 343 344 /** Write a byte array, using a varint for the size. */ 345 @Override writeBinary(byte[] buf)346 public void writeBinary(byte[] buf) throws TException { 347 writeBinary(buf, 0, buf.length); 348 } 349 writeBinary(byte[] buf, int offset, int length)350 private void writeBinary(byte[] buf, int offset, int length) throws TException { 351 writeVarint32(length); 352 trans_.write(buf, offset, length); 353 } 354 355 // 356 // These methods are called by structs, but don't actually have any wire 357 // output or purpose. 358 // 359 360 @Override writeMessageEnd()361 public void writeMessageEnd() throws TException {} 362 363 @Override writeMapEnd()364 public void writeMapEnd() throws TException {} 365 366 @Override writeListEnd()367 public void writeListEnd() throws TException {} 368 369 @Override writeSetEnd()370 public void writeSetEnd() throws TException {} 371 372 @Override writeFieldEnd()373 public void writeFieldEnd() throws TException {} 374 375 // 376 // Internal writing methods 377 // 378 379 /** 380 * Abstract method for writing the start of lists and sets. List and sets on the wire differ only 381 * by the type indicator. 382 */ writeCollectionBegin(byte elemType, int size)383 protected void writeCollectionBegin(byte elemType, int size) throws TException { 384 if (size <= 14) { 385 writeByteDirect(size << 4 | getCompactType(elemType)); 386 } else { 387 writeByteDirect(0xf0 | getCompactType(elemType)); 388 writeVarint32(size); 389 } 390 } 391 392 /** Write an i32 as a varint. Results in 1-5 bytes on the wire. */ writeVarint32(int n)393 private void writeVarint32(int n) throws TException { 394 int idx = 0; 395 while (true) { 396 if ((n & ~0x7F) == 0) { 397 buffer[idx++] = (byte) n; 398 break; 399 } else { 400 buffer[idx++] = (byte) ((n & 0x7F) | 0x80); 401 n >>>= 7; 402 } 403 } 404 trans_.write(buffer, 0, idx); 405 } 406 407 /** Write an i64 as a varint. Results in 1-10 bytes on the wire. */ writeVarint64(long n)408 private void writeVarint64(long n) throws TException { 409 int idx = 0; 410 while (true) { 411 if ((n & ~0x7FL) == 0) { 412 buffer[idx++] = (byte) n; 413 break; 414 } else { 415 buffer[idx++] = ((byte) ((n & 0x7F) | 0x80)); 416 n >>>= 7; 417 } 418 } 419 trans_.write(buffer, 0, idx); 420 } 421 422 /** 423 * Convert l into a zigzag long. This allows negative numbers to be represented compactly as a 424 * varint. 425 */ longToZigzag(long l)426 private long longToZigzag(long l) { 427 return (l << 1) ^ (l >> 63); 428 } 429 430 /** 431 * Convert n into a zigzag int. This allows negative numbers to be represented compactly as a 432 * varint. 433 */ intToZigZag(int n)434 private int intToZigZag(int n) { 435 return (n << 1) ^ (n >> 31); 436 } 437 438 /** Convert a long into little-endian bytes in buf starting at off and going until off+7. */ fixedLongToBytes(long n, byte[] buf, int off)439 private void fixedLongToBytes(long n, byte[] buf, int off) { 440 buf[off + 0] = (byte) ((n >> 56) & 0xff); 441 buf[off + 1] = (byte) ((n >> 48) & 0xff); 442 buf[off + 2] = (byte) ((n >> 40) & 0xff); 443 buf[off + 3] = (byte) ((n >> 32) & 0xff); 444 buf[off + 4] = (byte) ((n >> 24) & 0xff); 445 buf[off + 5] = (byte) ((n >> 16) & 0xff); 446 buf[off + 6] = (byte) ((n >> 8) & 0xff); 447 buf[off + 7] = (byte) (n & 0xff); 448 } 449 450 /** Convert a long into little-endian bytes in buf starting at off and going until off+7. */ fixedIntToBytes(int n, byte[] buf, int off)451 private void fixedIntToBytes(int n, byte[] buf, int off) { 452 buf[off + 0] = (byte) ((n >> 24) & 0xff); 453 buf[off + 1] = (byte) ((n >> 16) & 0xff); 454 buf[off + 2] = (byte) ((n >> 8) & 0xff); 455 buf[off + 3] = (byte) (n & 0xff); 456 } 457 458 /** 459 * Writes a byte without any possiblity of all that field header nonsense. Used internally by 460 * other writing methods that know they need to write a byte. 461 */ writeByteDirect(byte b)462 private void writeByteDirect(byte b) throws TException { 463 buffer[0] = b; 464 trans_.write(buffer, 0, 1); 465 } 466 467 /** Writes a byte without any possiblity of all that field header nonsense. */ writeByteDirect(int n)468 private void writeByteDirect(int n) throws TException { 469 writeByteDirect((byte) n); 470 } 471 472 // 473 // Reading methods. 474 // 475 476 /** Read a message header. */ 477 @Override readMessageBegin()478 public TMessage readMessageBegin() throws TException { 479 byte protocolId = readByte(); 480 if (protocolId != PROTOCOL_ID) { 481 throw new TProtocolException( 482 "Expected protocol id " 483 + Integer.toHexString(PROTOCOL_ID) 484 + " but got " 485 + Integer.toHexString(protocolId)); 486 } 487 byte versionAndType = readByte(); 488 version_ = (byte) (versionAndType & VERSION_MASK); 489 if (!(version_ <= VERSION && version_ >= VERSION_LOW)) { 490 throw new TProtocolException("Expected version " + VERSION + " but got " + version_); 491 } 492 byte type = (byte) ((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS); 493 int seqid = readVarint32(); 494 String messageName = readString(); 495 return new TMessage(messageName, type, seqid); 496 } 497 498 /** 499 * Read a struct begin. There's nothing on the wire for this, but it is our opportunity to push a 500 * new struct begin marker onto the field stack. 501 */ readStructBegin( Map<Integer, com.facebook.thrift.meta_data.FieldMetaData> metaDataMap)502 public TStruct readStructBegin( 503 Map<Integer, com.facebook.thrift.meta_data.FieldMetaData> metaDataMap) throws TException { 504 lastField_.push(lastFieldId_); 505 lastFieldId_ = 0; 506 return ANONYMOUS_STRUCT; 507 } 508 509 /** 510 * Doesn't actually consume any wire data, just removes the last field for this struct from the 511 * field stack. 512 */ 513 @Override readStructEnd()514 public void readStructEnd() throws TException { 515 // consume the last field we read off the wire. 516 lastFieldId_ = lastField_.pop(); 517 } 518 519 /** Read a field header off the wire. */ 520 @Override readFieldBegin()521 public TField readFieldBegin() throws TException { 522 byte type = readByte(); 523 524 // if it's a stop, then we can return immediately, as the struct is over. 525 if (type == TType.STOP) { 526 return TSTOP; 527 } 528 529 short fieldId; 530 531 // mask off the 4 MSB of the type header. it could contain a field id delta. 532 short modifier = (short) ((type & 0xf0) >> 4); 533 if (modifier == 0) { 534 // not a delta. look ahead for the zigzag varint field id. 535 fieldId = readI16(); 536 } else { 537 // has a delta. add the delta to the last read field id. 538 fieldId = (short) (lastFieldId_ + modifier); 539 } 540 541 TField field = new TField("", getTType((byte) (type & 0x0f)), fieldId); 542 543 // if this happens to be a boolean field, the value is encoded in the type 544 if (isBoolType(type)) { 545 // save the boolean value in a special instance variable. 546 boolValue_ = (byte) (type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE; 547 } 548 549 // push the new field onto the field stack so we can keep the deltas going. 550 lastFieldId_ = field.id; 551 return field; 552 } 553 554 /** 555 * Read a map header off the wire. If the size is zero, skip reading the key and value type. This 556 * means that 0-length maps will yield TMaps without the "correct" types. 557 */ 558 @Override readMapBegin()559 public TMap readMapBegin() throws TException { 560 int size = readVarint32(); 561 checkContainerReadLength(size); 562 byte keyAndValueType = size == 0 ? 0 : readByte(); 563 byte keyType = getTType((byte) (keyAndValueType >> 4)); 564 byte valueType = getTType((byte) (keyAndValueType & 0xf)); 565 if (size > 0) { 566 ensureMapHasEnough(size, keyType, valueType); 567 } 568 return new TMap(keyType, valueType, size); 569 } 570 571 /** 572 * Read a list header off the wire. If the list size is 0-14, the size will be packed into the 573 * element type header. If it's a longer list, the 4 MSB of the element type header will be 0xF, 574 * and a varint will follow with the true size. 575 */ 576 @Override readListBegin()577 public TList readListBegin() throws TException { 578 byte size_and_type = readByte(); 579 int size = (size_and_type >> 4) & 0x0f; 580 if (size == 15) { 581 size = readVarint32(); 582 } 583 checkContainerReadLength(size); 584 byte type = getTType(size_and_type); 585 ensureContainerHasEnough(size, type); 586 return new TList(type, size); 587 } 588 589 /** 590 * Read a set header off the wire. If the set size is 0-14, the size will be packed into the 591 * element type header. If it's a longer set, the 4 MSB of the element type header will be 0xF, 592 * and a varint will follow with the true size. 593 */ 594 @Override readSetBegin()595 public TSet readSetBegin() throws TException { 596 return new TSet(readListBegin()); 597 } 598 599 /** 600 * Read a boolean off the wire. If this is a boolean field, the value should already have been 601 * read during readFieldBegin, so we'll just consume the pre-stored value. Otherwise, read a byte. 602 */ 603 @Override readBool()604 public boolean readBool() throws TException { 605 if (boolValue_ != null) { 606 boolean result = boolValue_.booleanValue(); 607 boolValue_ = null; 608 return result; 609 } 610 return readByte() == Types.BOOLEAN_TRUE; 611 } 612 613 /** Read a single byte off the wire. Nothing interesting here. */ 614 @Override readByte()615 public byte readByte() throws TException { 616 byte b; 617 if (trans_.getBytesRemainingInBuffer() > 0) { 618 b = trans_.getBuffer()[trans_.getBufferPosition()]; 619 trans_.consumeBuffer(1); 620 } else { 621 trans_.readAll(buffer, 0, 1); 622 b = buffer[0]; 623 } 624 return b; 625 } 626 627 /** Read an i16 from the wire as a zigzag varint. */ 628 @Override readI16()629 public short readI16() throws TException { 630 return (short) zigzagToInt(readVarint32()); 631 } 632 633 /** Read an i32 from the wire as a zigzag varint. */ 634 @Override readI32()635 public int readI32() throws TException { 636 return zigzagToInt(readVarint32()); 637 } 638 639 /** Read an i64 from the wire as a zigzag varint. */ 640 @Override readI64()641 public long readI64() throws TException { 642 return zigzagToLong(readVarint64()); 643 } 644 645 /** No magic here - just read a double off the wire. */ 646 @Override readDouble()647 public double readDouble() throws TException { 648 trans_.readAll(buffer, 0, 8); 649 long value; 650 if (version_ >= VERSION_DOUBLE_BE) { 651 value = bytesToLong(buffer); 652 } else { 653 value = bytesToLongLE(buffer); 654 } 655 return Double.longBitsToDouble(value); 656 } 657 658 /** No magic here - just read a float off the wire. */ 659 @Override readFloat()660 public float readFloat() throws TException { 661 trans_.readAll(buffer, 0, 4); 662 int value = bytesToInt(buffer); 663 return Float.intBitsToFloat(value); 664 } 665 666 /** Reads a byte[] (via readBinary), and then UTF-8 decodes it. */ 667 @Override readString()668 public String readString() throws TException { 669 int length = readVarint32(); 670 checkContentReadLength(length); 671 672 if (length == 0) { 673 return ""; 674 } 675 676 if (trans_.getBytesRemainingInBuffer() >= length) { 677 String str = 678 new String( 679 trans_.getBuffer(), trans_.getBufferPosition(), length, StandardCharsets.UTF_8); 680 trans_.consumeBuffer(length); 681 return str; 682 } else { 683 return new String(readBinary(length), StandardCharsets.UTF_8); 684 } 685 } 686 687 /** Read a byte[] from the wire. */ 688 @Override readBinary()689 public byte[] readBinary() throws TException { 690 int length = readVarint32(); 691 checkContentReadLength(length); 692 return readBinary(length); 693 } 694 readBinary(int length)695 private byte[] readBinary(int length) throws TException { 696 if (length == 0) { 697 return new byte[0]; 698 } 699 700 ensureContainerHasEnough(length, TType.BYTE); 701 byte[] buf = new byte[length]; 702 trans_.readAll(buf, 0, length); 703 return buf; 704 } 705 checkContentReadLength(int length)706 private void checkContentReadLength(int length) throws TProtocolException { 707 if (length < 0) { 708 throw new TProtocolException(TProtocolException.NEGATIVE_SIZE, "Negative length: " + length); 709 } 710 if (stringLengthLimit_ > 0 && length > stringLengthLimit_) { 711 throw new TProtocolException( 712 TProtocolException.SIZE_LIMIT, 713 String.format( 714 "String/binary length %s exceeded max allowed %s", length, stringLengthLimit_)); 715 } 716 } 717 checkContainerReadLength(int length)718 private void checkContainerReadLength(int length) throws TProtocolException { 719 if (length < 0) { 720 throw new TProtocolException(TProtocolException.NEGATIVE_SIZE, "Negative length: " + length); 721 } 722 if (containerLengthLimit_ > 0 && length > containerLengthLimit_) { 723 throw new TProtocolException( 724 TProtocolException.SIZE_LIMIT, 725 String.format( 726 "Container length %s exceeded max allowed %s", length, containerLengthLimit_)); 727 } 728 } 729 730 // 731 // These methods are here for the struct to call, but don't have any wire 732 // encoding. 733 // 734 @Override readMessageEnd()735 public void readMessageEnd() throws TException {} 736 737 @Override readFieldEnd()738 public void readFieldEnd() throws TException {} 739 740 @Override readMapEnd()741 public void readMapEnd() throws TException {} 742 743 @Override readListEnd()744 public void readListEnd() throws TException {} 745 746 @Override readSetEnd()747 public void readSetEnd() throws TException {} 748 749 // 750 // Internal reading methods 751 // 752 753 /** 754 * Read an i32 from the wire as a varint. The MSB of each byte is set if there is another byte to 755 * follow. This can read up to 5 bytes. 756 */ readVarint32()757 private int readVarint32() throws TException { 758 int result = 0; 759 int shift = 0; 760 if (trans_.getBytesRemainingInBuffer() >= 5) { 761 byte[] buf = trans_.getBuffer(); 762 int pos = trans_.getBufferPosition(); 763 int off = 0; 764 while (true) { 765 byte b = buf[pos + off]; 766 result |= (int) (b & 0x7f) << shift; 767 if ((b & 0x80) != 0x80) { 768 break; 769 } 770 shift += 7; 771 off++; 772 } 773 trans_.consumeBuffer(off + 1); 774 } else { 775 while (true) { 776 byte b = readByte(); 777 result |= (int) (b & 0x7f) << shift; 778 if ((b & 0x80) != 0x80) { 779 break; 780 } 781 shift += 7; 782 } 783 } 784 return result; 785 } 786 787 /** 788 * Read an i64 from the wire as a proper varint. The MSB of each byte is set if there is another 789 * byte to follow. This can read up to 10 bytes. 790 */ readVarint64()791 private long readVarint64() throws TException { 792 int shift = 0; 793 long result = 0; 794 if (trans_.getBytesRemainingInBuffer() >= 10) { 795 byte[] buf = trans_.getBuffer(); 796 int pos = trans_.getBufferPosition(); 797 int off = 0; 798 while (true) { 799 byte b = buf[pos + off]; 800 result |= (long) (b & 0x7f) << shift; 801 if ((b & 0x80) != 0x80) { 802 break; 803 } 804 shift += 7; 805 off++; 806 } 807 trans_.consumeBuffer(off + 1); 808 } else { 809 while (true) { 810 byte b = readByte(); 811 result |= (long) (b & 0x7f) << shift; 812 if ((b & 0x80) != 0x80) { 813 break; 814 } 815 shift += 7; 816 } 817 } 818 return result; 819 } 820 821 // 822 // encoding helpers 823 // 824 825 /** Convert from zigzag int to int. */ zigzagToInt(int n)826 private int zigzagToInt(int n) { 827 return (n >>> 1) ^ -(n & 1); 828 } 829 830 /** Convert from zigzag long to long. */ zigzagToLong(long n)831 private long zigzagToLong(long n) { 832 return (n >>> 1) ^ -(n & 1); 833 } 834 835 /** 836 * Note that it's important that the mask bytes are long literals, otherwise they'll default to 837 * ints, and when you shift an int left 56 bits, you just get a messed up int. 838 */ bytesToLong(byte[] bytes)839 private long bytesToLong(byte[] bytes) { 840 return ((bytes[0] & 0xffL) << 56) 841 | ((bytes[1] & 0xffL) << 48) 842 | ((bytes[2] & 0xffL) << 40) 843 | ((bytes[3] & 0xffL) << 32) 844 | ((bytes[4] & 0xffL) << 24) 845 | ((bytes[5] & 0xffL) << 16) 846 | ((bytes[6] & 0xffL) << 8) 847 | ((bytes[7] & 0xffL)); 848 } 849 850 /* Little endian version of the above */ bytesToLongLE(byte[] bytes)851 private long bytesToLongLE(byte[] bytes) { 852 return ((bytes[7] & 0xffL) << 56) 853 | ((bytes[6] & 0xffL) << 48) 854 | ((bytes[5] & 0xffL) << 40) 855 | ((bytes[4] & 0xffL) << 32) 856 | ((bytes[3] & 0xffL) << 24) 857 | ((bytes[2] & 0xffL) << 16) 858 | ((bytes[1] & 0xffL) << 8) 859 | ((bytes[0] & 0xffL)); 860 } 861 bytesToInt(byte[] bytes)862 private int bytesToInt(byte[] bytes) { 863 return ((bytes[0] & 0xff) << 24) 864 | ((bytes[1] & 0xff) << 16) 865 | ((bytes[2] & 0xff) << 8) 866 | ((bytes[3] & 0xff)); 867 } 868 869 // 870 // type testing and converting 871 // 872 isBoolType(byte b)873 private boolean isBoolType(byte b) { 874 int lowerNibble = b & 0x0f; 875 return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE; 876 } 877 878 /** Given a TCompactProtocol.Types constant, convert it to its corresponding TType value. */ getTType(byte type)879 private byte getTType(byte type) throws TProtocolException { 880 switch ((byte) (type & 0x0f)) { 881 case TType.STOP: 882 return TType.STOP; 883 case Types.BOOLEAN_FALSE: 884 case Types.BOOLEAN_TRUE: 885 return TType.BOOL; 886 case Types.BYTE: 887 return TType.BYTE; 888 case Types.I16: 889 return TType.I16; 890 case Types.I32: 891 return TType.I32; 892 case Types.I64: 893 return TType.I64; 894 case Types.DOUBLE: 895 return TType.DOUBLE; 896 case Types.FLOAT: 897 return TType.FLOAT; 898 case Types.BINARY: 899 return TType.STRING; 900 case Types.LIST: 901 return TType.LIST; 902 case Types.SET: 903 return TType.SET; 904 case Types.MAP: 905 return TType.MAP; 906 case Types.STRUCT: 907 return TType.STRUCT; 908 default: 909 throw new TProtocolException("don't know what type: " + (byte) (type & 0x0f)); 910 } 911 } 912 913 /** Given a TType value, find the appropriate TCompactProtocol.Types constant. */ getCompactType(byte ttype)914 private byte getCompactType(byte ttype) { 915 return ttypeToCompactType[ttype]; 916 } 917 918 @Override typeMinimumSize(byte type)919 protected int typeMinimumSize(byte type) { 920 switch (type & 0x0f) { 921 case TType.BOOL: 922 case TType.BYTE: 923 case TType.I16: // because of variable length encoding 924 case TType.I32: // because of variable length encoding 925 case TType.I64: // because of variable length encoding 926 case TType.FLOAT: // because of variable length encoding 927 case TType.DOUBLE: // because of variable length encoding 928 case TType.STRING: 929 case TType.STRUCT: 930 case TType.MAP: 931 case TType.SET: 932 case TType.LIST: 933 case TType.ENUM: 934 return 1; 935 default: 936 throw new TProtocolException( 937 TProtocolException.INVALID_DATA, "Unexpected data type " + (byte) (type & 0x0f)); 938 } 939 } 940 } 941