/** * If we encounter a boolean field begin, save the TField here so it can * have the value incorporated. */ private TField booleanField_ = null;
/** * If we read a field header, and it's a boolean field, save the boolean * value here so that readBool can use it. */ private Boolean boolValue_ = null;
/** * Write a message header to the wire. Compact Protocol messages contain the * protocol version so we can migrate forwards in the future if need be. */ publicvoidwriteMessageBegin(TMessage message)throws TException { writeByteDirect(PROTOCOL_ID); writeByteDirect((VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)); writeVarint32(message.seqid); writeString(message.name); }
/** * Write a struct begin. This doesn't actually put anything on the wire. We * use it as an opportunity to put special placeholder markers on the field * stack so we can get the field id deltas correct. */ publicvoidwriteStructBegin(TStruct struct)throws TException { lastField_.push(lastFieldId_); lastFieldId_ = 0; }
/** * Write a struct end. This doesn't actually put anything on the wire. We use * this as an opportunity to pop the last field from the current struct off * of the field stack. */ publicvoidwriteStructEnd()throws TException { lastFieldId_ = lastField_.pop(); }
/** * Write a field header containing the field id and field type. If the * difference between the current field id and the last one is small (< 15), * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the * field id will follow the type header as a zigzag varint. */ publicvoidwriteFieldBegin(TField field)throws TException { if (field.type == TType.BOOL) { // we want to possibly include the value, so we'll wait. booleanField_ = field; } else { writeFieldBeginInternal(field, (byte)-1); } }
/** * The workhorse of writeFieldBegin. It has the option of doing a * 'type override' of the type header. This is used specifically in the * boolean field case. */ privatevoidwriteFieldBeginInternal(TField field, byte typeOverride)throws TException { // short lastField = lastField_.pop();
// if there's a type override, use that. byte typeToWrite = typeOverride == -1 ? getCompactType(field.type) : typeOverride;
// check if we can use delta encoding for the field id if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15) { // write them together writeByteDirect((field.id - lastFieldId_) << 4 | typeToWrite); } else { // write them separate writeByteDirect(typeToWrite); writeI16(field.id); }
/** * Write the STOP symbol so we know there are no more fields in this struct. */ publicvoidwriteFieldStop()throws TException { writeByteDirect(TType.STOP); }
/** * Write a map header. If the map is empty, omit the key and value type * headers, as we don't need any additional information to skip it. */ publicvoidwriteMapBegin(TMap map)throws TException { if (map.size == 0) { writeByteDirect(0); } else { writeVarint32(map.size); writeByteDirect(getCompactType(map.keyType) << 4 | getCompactType(map.valueType)); } } /** * Write a list header. */ publicvoidwriteListBegin(TList list)throws TException { writeCollectionBegin(list.elemType, list.size); }
/** * Write a set header. */ publicvoidwriteSetBegin(TSet set)throws TException { writeCollectionBegin(set.elemType, set.size); }
/** * Write a boolean value. Potentially, this could be a boolean field, in * which case the field header info isn't written yet. If so, decide what the * right type header is for the value and then write the field header. * Otherwise, write a single byte. */ publicvoidwriteBool(boolean b)throws TException { if (booleanField_ != null) { // we haven't written the field header yet writeFieldBeginInternal(booleanField_, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); booleanField_ = null; } else { // we're not part of a field, so just write the value. writeByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); } } publicvoidwriteByte(byte b)throws TException { writeByteDirect(b); } //ZigZag编码:16位 publicvoidwriteI16(short i16)throws TException { writeVarint32(intToZigZag(i16)); } //ZigZag编码:32位 publicvoidwriteI32(int i32)throws TException { writeVarint32(intToZigZag(i32)); } //ZigZag编码:64位 publicvoidwriteI64(long i64)throws TException { writeVarint64(longToZigzag(i64)); }
/** * Write a byte array, using a varint for the size. */ publicvoidwriteBinary(ByteBuffer bin)throws TException { int length = bin.limit() - bin.position(); writeBinary(bin.array(), bin.position() + bin.arrayOffset(), length); }
privatevoidwriteBinary(byte[] buf, int offset, int length)throws TException { writeVarint32(length); trans_.write(buf, offset, length); }
/** * Abstract method for writing the start of lists and sets. List and sets on * the wire differ only by the type indicator. */ protectedvoidwriteCollectionBegin(byte elemType, int size)throws TException { if (size <= 14) { writeByteDirect(size << 4 | getCompactType(elemType)); } else { writeByteDirect(0xf0 | getCompactType(elemType)); writeVarint32(size); } }
/** * Write an i32 as a varint. Results in 1-5 bytes on the wire. * TODO: make a permanent buffer like writeVarint64? */ byte[] i32buf = newbyte[5]; privatevoidwriteVarint32(int n)throws TException { int idx = 0; while (true) { if ((n & ~0x7F) == 0) { i32buf[idx++] = (byte)n; // writeByteDirect((byte)n); break; // return; } else { i32buf[idx++] = (byte)((n & 0x7F) | 0x80); // writeByteDirect((byte)((n & 0x7F) | 0x80)); n >>>= 7; } } trans_.write(i32buf, 0, idx); }
/** * Write an i64 as a varint. Results in 1-10 bytes on the wire. */ byte[] varint64out = newbyte[10]; privatevoidwriteVarint64(long n)throws TException { int idx = 0; while (true) { if ((n & ~0x7FL) == 0) { varint64out[idx++] = (byte)n; break; } else { varint64out[idx++] = ((byte)((n & 0x7F) | 0x80)); n >>>= 7; } } trans_.write(varint64out, 0, idx); }
/** * Convert l into a zigzag long. This allows negative numbers to be * represented compactly as a varint. */ privatelonglongToZigzag(long l){ return (l << 1) ^ (l >> 63); }
/** * Convert n into a zigzag int. This allows negative numbers to be * represented compactly as a varint. */ privateintintToZigZag(int n){ return (n << 1) ^ (n >> 31); }
/** * Convert a long into little-endian bytes in buf starting at off and going * until off+7. */ privatevoidfixedLongToBytes(long n, byte[] buf, int off){ buf[off+0] = (byte)( n & 0xff); buf[off+1] = (byte)((n >> 8 ) & 0xff); buf[off+2] = (byte)((n >> 16) & 0xff); buf[off+3] = (byte)((n >> 24) & 0xff); buf[off+4] = (byte)((n >> 32) & 0xff); buf[off+5] = (byte)((n >> 40) & 0xff); buf[off+6] = (byte)((n >> 48) & 0xff); buf[off+7] = (byte)((n >> 56) & 0xff); }
/** * Writes a byte without any possibility of all that field header nonsense. * Used internally by other writing methods that know they need to write a byte. */ privatebyte[] byteDirectBuffer = newbyte[1]; privatevoidwriteByteDirect(byte b)throws TException { byteDirectBuffer[0] = b; trans_.write(byteDirectBuffer); }
/** * Writes a byte without any possibility of all that field header nonsense. */ privatevoidwriteByteDirect(int n)throws TException { writeByteDirect((byte)n); }
// // Reading methods. //
/** * Read a message header. */ public TMessage readMessageBegin()throws TException { byte protocolId = readByte(); if (protocolId != PROTOCOL_ID) { thrownew TProtocolException("Expected protocol id " + Integer.toHexString(PROTOCOL_ID) + " but got " + Integer.toHexString(protocolId)); } byte versionAndType = readByte(); byte version = (byte)(versionAndType & VERSION_MASK); if (version != VERSION) { thrownew TProtocolException("Expected version " + VERSION + " but got " + version); } byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03); int seqid = readVarint32(); String messageName = readString(); returnnew TMessage(messageName, type, seqid); }
/** * Read a struct begin. There's nothing on the wire for this, but it is our * opportunity to push a new struct begin marker onto the field stack. */ public TStruct readStructBegin()throws TException { lastField_.push(lastFieldId_); lastFieldId_ = 0; return ANONYMOUS_STRUCT; }
/** * Doesn't actually consume any wire data, just removes the last field for * this struct from the field stack. */ publicvoidreadStructEnd()throws TException { // consume the last field we read off the wire. lastFieldId_ = lastField_.pop(); } /** * Read a field header off the wire. */ public TField readFieldBegin()throws TException { byte type = readByte();
// if it's a stop, then we can return immediately, as the struct is over. if (type == TType.STOP) { return TSTOP; }
short fieldId;
// mask off the 4 MSB of the type header. it could contain a field id delta. short modifier = (short)((type & 0xf0) >> 4); if (modifier == 0) { // not a delta. look ahead for the zigzag varint field id. fieldId = readI16(); } else { // has a delta. add the delta to the last read field id. fieldId = (short)(lastFieldId_ + modifier); }
TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
// if this happens to be a boolean field, the value is encoded in the type if (isBoolType(type)) { // save the boolean value in a special instance variable. boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE; }
// push the new field onto the field stack so we can keep the deltas going. lastFieldId_ = field.id; return field; }
/** * Read a map header off the wire. If the size is zero, skip reading the key * and value type. This means that 0-length maps will yield TMaps without the * "correct" types. */ public TMap readMapBegin()throws TException { int size = readVarint32(); byte keyAndValueType = size == 0 ? 0 : readByte(); returnnew TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size); }
/** * Read a list header off the wire. If the list size is 0-14, the size will * be packed into the element type header. If it's a longer list, the 4 MSB * of the element type header will be 0xF, and a varint will follow with the * true size. */ public TList readListBegin()throws TException { byte size_and_type = readByte(); int size = (size_and_type >> 4) & 0x0f; if (size == 15) { size = readVarint32(); } byte type = getTType(size_and_type); returnnew TList(type, size); }
/** * Read a set header off the wire. If the set size is 0-14, the size will * be packed into the element type header. If it's a longer set, the 4 MSB * of the element type header will be 0xF, and a varint will follow with the * true size. */ public TSet readSetBegin()throws TException { returnnew TSet(readListBegin()); }
/** * Read a boolean off the wire. If this is a boolean field, the value should * already have been read during readFieldBegin, so we'll just consume the * pre-stored value. Otherwise, read a byte. */ publicbooleanreadBool()throws TException { if (boolValue_ != null) { boolean result = boolValue_.booleanValue(); boolValue_ = null; return result; } return readByte() == Types.BOOLEAN_TRUE; }
byte[] byteRawBuf = newbyte[1]; /** * Read a single byte off the wire. Nothing interesting here. */ publicbytereadByte()throws TException { byte b; if (trans_.getBytesRemainingInBuffer() > 0) { b = trans_.getBuffer()[trans_.getBufferPosition()]; trans_.consumeBuffer(1); } else { trans_.readAll(byteRawBuf, 0, 1); b = byteRawBuf[0]; } return b; }
/** * Read an i16 from the wire as a zigzag varint. */ publicshortreadI16()throws TException { return (short)zigzagToInt(readVarint32()); }
/** * Read an i32 from the wire as a zigzag varint. */ publicintreadI32()throws TException { return zigzagToInt(readVarint32()); }
/** * Read an i64 from the wire as a zigzag varint. */ publiclongreadI64()throws TException { return zigzagToLong(readVarint64()); }
/** * No magic here - just read a double off the wire. */ publicdoublereadDouble()throws TException { byte[] longBits = newbyte[8]; trans_.readAll(longBits, 0, 8); return Double.longBitsToDouble(bytesToLong(longBits)); }
/** * Reads a byte[] (via readBinary), and then UTF-8 decodes it. */ public String readString()throws TException { int length = readVarint32();
/** * Read a byte[] from the wire. */ public ByteBuffer readBinary()throws TException { int length = readVarint32(); if (length == 0) return ByteBuffer.wrap(newbyte[0]);
// // These methods are here for the struct to call, but don't have any wire // encoding. // publicvoidreadMessageEnd()throws TException {} publicvoidreadFieldEnd()throws TException {} publicvoidreadMapEnd()throws TException {} publicvoidreadListEnd()throws TException {} publicvoidreadSetEnd()throws TException {}
// // Internal reading methods //
/** * Read an i32 from the wire as a varint. The MSB of each byte is set * if there is another byte to follow. This can read up to 5 bytes. */ privateintreadVarint32()throws TException { int result = 0; int shift = 0; if (trans_.getBytesRemainingInBuffer() >= 5) { byte[] buf = trans_.getBuffer(); int pos = trans_.getBufferPosition(); int off = 0; while (true) { byte b = buf[pos+off]; result |= (int) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) break; shift += 7; off++; } trans_.consumeBuffer(off+1); } else { while (true) { byte b = readByte(); result |= (int) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) break; shift += 7; } } return result; }
/** * Read an i64 from the wire as a proper varint. The MSB of each byte is set * if there is another byte to follow. This can read up to 10 bytes. */ privatelongreadVarint64()throws TException { int shift = 0; long result = 0; if (trans_.getBytesRemainingInBuffer() >= 10) { byte[] buf = trans_.getBuffer(); int pos = trans_.getBufferPosition(); int off = 0; while (true) { byte b = buf[pos+off]; result |= (long) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) break; shift += 7; off++; } trans_.consumeBuffer(off+1); } else { while (true) { byte b = readByte(); result |= (long) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) break; shift +=7; } } return result; }
// // encoding helpers //
/** * Convert from zigzag int to int. */ privateintzigzagToInt(int n){ return (n >>> 1) ^ -(n & 1); }
/** * Convert from zigzag long to long. */ privatelongzigzagToLong(long n){ return (n >>> 1) ^ -(n & 1); }
/** * Note that it's important that the mask bytes are long literals, * otherwise they'll default to ints, and when you shift an int left 56 bits, * you just get a messed up int. */ privatelongbytesToLong(byte[] bytes){ return ((bytes[7] & 0xffL) << 56) | ((bytes[6] & 0xffL) << 48) | ((bytes[5] & 0xffL) << 40) | ((bytes[4] & 0xffL) << 32) | ((bytes[3] & 0xffL) << 24) | ((bytes[2] & 0xffL) << 16) | ((bytes[1] & 0xffL) << 8) | ((bytes[0] & 0xffL)); }
// // type testing and converting //
privatebooleanisBoolType(byte b){ int lowerNibble = b & 0x0f; return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE; }
/** * Given a TCompactProtocol.Types constant, convert it to its corresponding * TType value. */ privatebytegetTType(byte type)throws TProtocolException { switch ((byte)(type & 0x0f)) { case TType.STOP: return TType.STOP; case Types.BOOLEAN_FALSE: case Types.BOOLEAN_TRUE: return TType.BOOL; case Types.BYTE: return TType.BYTE; case Types.I16: return TType.I16; case Types.I32: return TType.I32; case Types.I64: return TType.I64; case Types.DOUBLE: return TType.DOUBLE; case Types.BINARY: return TType.STRING; case Types.LIST: return TType.LIST; case Types.SET: return TType.SET; case Types.MAP: return TType.MAP; case Types.STRUCT: return TType.STRUCT; default: thrownew TProtocolException("don't know what type: " + (byte)(type & 0x0f)); } }
/** * Given a TType value, find the appropriate TCompactProtocol.Types constant. */ privatebytegetCompactType(byte ttype){ return ttypeToCompactType[ttype]; } }
publicvoidwriteBool(boolean b)throws TException { if (booleanField_ != null) { // we haven't written the field header yet writeFieldBeginInternal(booleanField_, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); booleanField_ = null; } else { // we're not part of a field, so just write the value. writeByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); } }
public TField readFieldBegin()throws TException { byte type = readByte(); if (type == TType.STOP) { return TSTOP; }
short fieldId;
// 主要是计算field的id // 写入是以高4为未field id的偏移 所以需要将field 的偏移算出来 short modifier = (short)((type & 0xf0) >> 4); if (modifier == 0) { //如果否没有偏移 直接 读取16位的field id fieldId = readI16(); } else { // 否则 偏移 + 组内编号得到 field整整的id fieldId = (short)(lastFieldId_ + modifier); } // 转换为 type TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
// if this happens to be a boolean field, the value is encoded in the type if (isBoolType(type)) { // save the boolean value in a special instance variable. boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE; }