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