--- /dev/null
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */\r
+\r
+using System;\r
+using System.Text;\r
+using Thrift.Transport;\r
+using System.Collections;\r
+using System.IO;\r
+using System.Collections.Generic;\r
+\r
+namespace Thrift.Protocol\r
+{\r
+ public class TCompactProtocol : TProtocol\r
+ {\r
+ private static TStruct ANONYMOUS_STRUCT = new TStruct("");\r
+ private static TField TSTOP = new TField("", TType.Stop, (short)0);\r
+\r
+ private static byte[] ttypeToCompactType = new byte[16];\r
+\r
+ private const byte PROTOCOL_ID = 0x82;\r
+ private const byte VERSION = 1;\r
+ private const byte VERSION_MASK = 0x1f; // 0001 1111\r
+ private const byte TYPE_MASK = 0xE0; // 1110 0000\r
+ private const int TYPE_SHIFT_AMOUNT = 5;\r
+\r
+ /**
+ * All of the on-wire type codes.
+ */\r
+ private static class Types\r
+ {\r
+ public const byte STOP = 0x00;\r
+ public const byte BOOLEAN_TRUE = 0x01;\r
+ public const byte BOOLEAN_FALSE = 0x02;\r
+ public const byte BYTE = 0x03;\r
+ public const byte I16 = 0x04;\r
+ public const byte I32 = 0x05;\r
+ public const byte I64 = 0x06;\r
+ public const byte DOUBLE = 0x07;\r
+ public const byte BINARY = 0x08;\r
+ public const byte LIST = 0x09;\r
+ public const byte SET = 0x0A;\r
+ public const byte MAP = 0x0B;\r
+ public const byte STRUCT = 0x0C;\r
+ }\r
+\r
+ /**
+ * Used to keep track of the last field for the current and previous structs,
+ * so we can do the delta stuff.
+ */\r
+ private Stack<short> lastField_ = new Stack<short>(15);\r
+\r
+ private short lastFieldId_ = 0;\r
+\r
+ /**
+ * If we encounter a boolean field begin, save the TField here so it can
+ * have the value incorporated.
+ */\r
+ private Nullable<TField> booleanField_;\r
+\r
+ /**
+ * If we Read a field header, and it's a boolean field, save the boolean
+ * value here so that ReadBool can use it.
+ */\r
+ private Nullable<Boolean> boolValue_;\r
+\r
+\r
+ #region CompactProtocol Factory\r
+\r
+ /**
+ * Factory
+ */\r
+ public class Factory : TProtocolFactory\r
+ {\r
+ public Factory() { }\r
+\r
+ public TProtocol GetProtocol(TTransport trans)\r
+ {\r
+ return new TCompactProtocol(trans);\r
+ }\r
+ }\r
+\r
+ #endregion\r
+\r
+ public TCompactProtocol(TTransport trans)\r
+ : base(trans)\r
+ {\r
+ ttypeToCompactType[(int)TType.Stop] = Types.STOP;\r
+ ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE;\r
+ ttypeToCompactType[(int)TType.Byte] = Types.BYTE;\r
+ ttypeToCompactType[(int)TType.I16] = Types.I16;\r
+ ttypeToCompactType[(int)TType.I32] = Types.I32;\r
+ ttypeToCompactType[(int)TType.I64] = Types.I64;\r
+ ttypeToCompactType[(int)TType.Double] = Types.DOUBLE;\r
+ ttypeToCompactType[(int)TType.String] = Types.BINARY;\r
+ ttypeToCompactType[(int)TType.List] = Types.LIST;\r
+ ttypeToCompactType[(int)TType.Set] = Types.SET;\r
+ ttypeToCompactType[(int)TType.Map] = Types.MAP;\r
+ ttypeToCompactType[(int)TType.Struct] = Types.STRUCT;\r
+ }\r
+\r
+ public void reset()\r
+ {\r
+ lastField_.Clear();\r
+ lastFieldId_ = 0;\r
+ }\r
+\r
+ #region Write Methods\r
+\r
+\r
+ /**
+ * 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.
+ */\r
+ private byte[] byteDirectBuffer = new byte[1];\r
+ private void WriteByteDirect(byte b)\r
+ {\r
+ byteDirectBuffer[0] = b;\r
+ trans.Write(byteDirectBuffer);\r
+ }\r
+\r
+ /**
+ * Writes a byte without any possibility of all that field header nonsense.
+ */\r
+ private void WriteByteDirect(int n)\r
+ {\r
+ WriteByteDirect((byte)n);\r
+ }\r
+\r
+ /**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ * TODO: make a permanent buffer like WriteVarint64?
+ */\r
+ byte[] i32buf = new byte[5];\r
+ private void WriteVarint32(uint n)\r
+ {\r
+ int idx = 0;\r
+ while (true)\r
+ {\r
+ if ((n & ~0x7F) == 0)\r
+ {\r
+ i32buf[idx++] = (byte)n;\r
+ // WriteByteDirect((byte)n);\r
+ break;\r
+ // return;\r
+ }\r
+ else\r
+ {\r
+ i32buf[idx++] = (byte)((n & 0x7F) | 0x80);\r
+ // WriteByteDirect((byte)((n & 0x7F) | 0x80));\r
+ n >>= 7;\r
+ }\r
+ }\r
+ trans.Write(i32buf, 0, idx);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteMessageBegin(TMessage message)\r
+ {\r
+ WriteByteDirect(PROTOCOL_ID);\r
+ WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)));\r
+ WriteVarint32((uint)message.SeqID);\r
+ WriteString(message.Name);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteStructBegin(TStruct strct)\r
+ {\r
+ lastField_.Push(lastFieldId_);\r
+ lastFieldId_ = 0;\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteStructEnd()\r
+ {\r
+ lastFieldId_ = lastField_.Pop();\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteFieldBegin(TField field)\r
+ {\r
+ if (field.Type == TType.Bool)\r
+ {\r
+ // we want to possibly include the value, so we'll wait.\r
+ booleanField_ = field;\r
+ }\r
+ else\r
+ {\r
+ WriteFieldBeginInternal(field, 0xFF);\r
+ }\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ private void WriteFieldBeginInternal(TField field, byte typeOverride)\r
+ {\r
+ // short lastField = lastField_.Pop();\r
+\r
+ // if there's a type override, use that.\r
+ byte typeToWrite = typeOverride == 0xFF ? getCompactType(field.Type) : typeOverride;\r
+\r
+ // check if we can use delta encoding for the field id\r
+ if (field.ID > lastFieldId_ && field.ID - lastFieldId_ <= 15)\r
+ {\r
+ // Write them together\r
+ WriteByteDirect((field.ID - lastFieldId_) << 4 | typeToWrite);\r
+ }\r
+ else\r
+ {\r
+ // Write them separate\r
+ WriteByteDirect(typeToWrite);\r
+ WriteI16(field.ID);\r
+ }\r
+\r
+ lastFieldId_ = field.ID;\r
+ // lastField_.push(field.id);\r
+ }\r
+\r
+ /**
+ * Write the STOP symbol so we know there are no more fields in this struct.
+ */\r
+ public override void WriteFieldStop()\r
+ {\r
+ WriteByteDirect(Types.STOP);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteMapBegin(TMap map)\r
+ {\r
+ if (map.Count == 0)\r
+ {\r
+ WriteByteDirect(0);\r
+ }\r
+ else\r
+ {\r
+ WriteVarint32((uint)map.Count);\r
+ WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType));\r
+ }\r
+ }\r
+\r
+ /**
+ * Write a list header.
+ */\r
+ public override void WriteListBegin(TList list)\r
+ {\r
+ WriteCollectionBegin(list.ElementType, list.Count);\r
+ }\r
+\r
+ /**
+ * Write a set header.
+ */\r
+ public override void WriteSetBegin(TSet set)\r
+ {\r
+ WriteCollectionBegin(set.ElementType, set.Count);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override void WriteBool(Boolean b)\r
+ {\r
+ if (booleanField_ != null)\r
+ {\r
+ // we haven't written the field header yet\r
+ WriteFieldBeginInternal(booleanField_.Value, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);\r
+ booleanField_ = null;\r
+ }\r
+ else\r
+ {\r
+ // we're not part of a field, so just Write the value.\r
+ WriteByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);\r
+ }\r
+ }\r
+\r
+ /**
+ * Write a byte. Nothing to see here!
+ */\r
+ public override void WriteByte(byte b)\r
+ {\r
+ WriteByteDirect(b);\r
+ }\r
+\r
+ /**
+ * Write an I16 as a zigzag varint.
+ */\r
+ public override void WriteI16(short i16)\r
+ {\r
+ WriteVarint32(intToZigZag(i16));\r
+ }\r
+\r
+ /**
+ * Write an i32 as a zigzag varint.
+ */\r
+ public override void WriteI32(int i32)\r
+ {\r
+ WriteVarint32(intToZigZag(i32));\r
+ }\r
+\r
+ /**
+ * Write an i64 as a zigzag varint.
+ */\r
+ public override void WriteI64(long i64)\r
+ {\r
+ WriteVarint64(longToZigzag(i64));\r
+ }\r
+\r
+ /**
+ * Write a double to the wire as 8 bytes.
+ */\r
+ public override void WriteDouble(double dub)\r
+ {\r
+ byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };\r
+ fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0);\r
+ trans.Write(data);\r
+ }\r
+\r
+ /**
+ * Write a string to the wire with a varint size preceding.
+ */\r
+ public override void WriteString(String str)\r
+ {\r
+ byte[] bytes = UTF8Encoding.UTF8.GetBytes(str);\r
+ WriteBinary(bytes, 0, bytes.Length);\r
+ }\r
+\r
+ /**
+ * Write a byte array, using a varint for the size.
+ */\r
+ public override void WriteBinary(byte[] bin)\r
+ {\r
+ WriteBinary(bin, 0, bin.Length);\r
+ }\r
+\r
+ private void WriteBinary(byte[] buf, int offset, int length)\r
+ {\r
+ WriteVarint32((uint)length);\r
+ trans.Write(buf, offset, length);\r
+ }\r
+\r
+ //\r
+ // These methods are called by structs, but don't actually have any wire \r
+ // output or purpose.\r
+ // \r
+\r
+ public override void WriteMessageEnd() { }\r
+ public override void WriteMapEnd() { }\r
+ public override void WriteListEnd() { }\r
+ public override void WriteSetEnd() { }\r
+ public override void WriteFieldEnd() { }\r
+\r
+ //\r
+ // Internal writing methods\r
+ //\r
+\r
+ /**
+ * Abstract method for writing the start of lists and sets. List and sets on
+ * the wire differ only by the type indicator.
+ */\r
+ protected void WriteCollectionBegin(TType elemType, int size)\r
+ {\r
+ if (size <= 14)\r
+ {\r
+ WriteByteDirect(size << 4 | getCompactType(elemType));\r
+ }\r
+ else\r
+ {\r
+ WriteByteDirect(0xf0 | getCompactType(elemType));\r
+ WriteVarint32((uint)size);\r
+ }\r
+ }\r
+\r
+ /**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */\r
+ byte[] varint64out = new byte[10];\r
+ private void WriteVarint64(ulong n)\r
+ {\r
+ int idx = 0;\r
+ while (true)\r
+ {\r
+ if ((n & ~(ulong)0x7FL) == 0)\r
+ {\r
+ varint64out[idx++] = (byte)n;\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ varint64out[idx++] = ((byte)((n & 0x7F) | 0x80));\r
+ n >>= 7;\r
+ }\r
+ }\r
+ trans.Write(varint64out, 0, idx);\r
+ }\r
+\r
+ /**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */\r
+ private ulong longToZigzag(long n)\r
+ {\r
+ return (ulong)(((ulong)n << 1) ^ ((ulong)n >> 63));\r
+ }\r
+\r
+ /**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */\r
+ private uint intToZigZag(int n)\r
+ {\r
+ return (uint)(((uint)n << 1) ^ ((uint)n >> 31));\r
+ }\r
+\r
+ /**
+ * Convert a long into little-endian bytes in buf starting at off and going
+ * until off+7.
+ */\r
+ private void fixedLongToBytes(long n, byte[] buf, int off)\r
+ {\r
+ buf[off + 0] = (byte)(n & 0xff);\r
+ buf[off + 1] = (byte)((n >> 8) & 0xff);\r
+ buf[off + 2] = (byte)((n >> 16) & 0xff);\r
+ buf[off + 3] = (byte)((n >> 24) & 0xff);\r
+ buf[off + 4] = (byte)((n >> 32) & 0xff);\r
+ buf[off + 5] = (byte)((n >> 40) & 0xff);\r
+ buf[off + 6] = (byte)((n >> 48) & 0xff);\r
+ buf[off + 7] = (byte)((n >> 56) & 0xff);\r
+ }\r
+\r
+ #endregion\r
+\r
+ #region ReadMethods\r
+\r
+ /**
+ * Read a message header.
+ */\r
+ public override TMessage ReadMessageBegin()\r
+ {\r
+ byte protocolId = ReadByte();\r
+ if (protocolId != PROTOCOL_ID)\r
+ {\r
+ throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X"));\r
+ }\r
+ byte versionAndType = ReadByte();\r
+ byte version = (byte)(versionAndType & VERSION_MASK);\r
+ if (version != VERSION)\r
+ {\r
+ throw new TProtocolException("Expected version " + VERSION + " but got " + version);\r
+ }\r
+ byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);\r
+ int seqid = (int)ReadVarint32();\r
+ String messageName = ReadString();\r
+ return new TMessage(messageName, (TMessageType)type, seqid);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override TStruct ReadStructBegin()\r
+ {\r
+ lastField_.Push(lastFieldId_);\r
+ lastFieldId_ = 0;\r
+ return ANONYMOUS_STRUCT;\r
+ }\r
+\r
+ /**
+ * Doesn't actually consume any wire data, just removes the last field for
+ * this struct from the field stack.
+ */\r
+ public override void ReadStructEnd()\r
+ {\r
+ // consume the last field we Read off the wire.\r
+ lastFieldId_ = lastField_.Pop();\r
+ }\r
+\r
+ /**
+ * Read a field header off the wire.
+ */\r
+ public override TField ReadFieldBegin()\r
+ {\r
+ byte type = ReadByte();\r
+\r
+ // if it's a stop, then we can return immediately, as the struct is over.\r
+ if (type == Types.STOP)\r
+ {\r
+ return TSTOP;\r
+ }\r
+\r
+ short fieldId;\r
+\r
+ // mask off the 4 MSB of the type header. it could contain a field id delta.\r
+ short modifier = (short)((type & 0xf0) >> 4);\r
+ if (modifier == 0)\r
+ {\r
+ // not a delta. look ahead for the zigzag varint field id.\r
+ fieldId = ReadI16();\r
+ }\r
+ else\r
+ {\r
+ // has a delta. add the delta to the last Read field id.\r
+ fieldId = (short)(lastFieldId_ + modifier);\r
+ }\r
+\r
+ TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);\r
+\r
+ // if this happens to be a boolean field, the value is encoded in the type\r
+ if (isBoolType(type))\r
+ {\r
+ // save the boolean value in a special instance variable.\r
+ boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? true : false;\r
+ }\r
+\r
+ // push the new field onto the field stack so we can keep the deltas going.\r
+ lastFieldId_ = field.ID;\r
+ return field;\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override TMap ReadMapBegin()\r
+ {\r
+ int size = (int)ReadVarint32();\r
+ byte keyAndValueType = size == 0 ? (byte)0 : ReadByte();\r
+ return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override TList ReadListBegin()\r
+ {\r
+ byte size_and_type = ReadByte();\r
+ int size = (size_and_type >> 4) & 0x0f;\r
+ if (size == 15)\r
+ {\r
+ size = (int)ReadVarint32();\r
+ }\r
+ TType type = getTType(size_and_type);\r
+ return new TList(type, size);\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override TSet ReadSetBegin()\r
+ {\r
+ return new TSet(ReadListBegin());\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ public override Boolean ReadBool()\r
+ {\r
+ if (boolValue_ != null)\r
+ {\r
+ bool result = boolValue_.Value;\r
+ boolValue_ = null;\r
+ return result;\r
+ }\r
+ return ReadByte() == Types.BOOLEAN_TRUE;\r
+ }\r
+\r
+ byte[] byteRawBuf = new byte[1];\r
+ /**
+ * Read a single byte off the wire. Nothing interesting here.
+ */\r
+ public override byte ReadByte()\r
+ {\r
+ trans.ReadAll(byteRawBuf, 0, 1);\r
+ return byteRawBuf[0];\r
+ }\r
+\r
+ /**
+ * Read an i16 from the wire as a zigzag varint.
+ */\r
+ public override short ReadI16()\r
+ {\r
+ return (short)zigzagToInt(ReadVarint32());\r
+ }\r
+\r
+ /**
+ * Read an i32 from the wire as a zigzag varint.
+ */\r
+ public override int ReadI32()\r
+ {\r
+ return zigzagToInt(ReadVarint32());\r
+ }\r
+\r
+ /**
+ * Read an i64 from the wire as a zigzag varint.
+ */\r
+ public override long ReadI64()\r
+ {\r
+ return zigzagToLong(ReadVarint64());\r
+ }\r
+\r
+ /**
+ * No magic here - just Read a double off the wire.
+ */\r
+ public override double ReadDouble()\r
+ {\r
+ byte[] longBits = new byte[8];\r
+ trans.ReadAll(longBits, 0, 8);\r
+ return BitConverter.Int64BitsToDouble(bytesToLong(longBits));\r
+ }\r
+\r
+ /**
+ * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+ */\r
+ public override String ReadString()\r
+ {\r
+ int length = (int)ReadVarint32();\r
+\r
+ if (length == 0)\r
+ {\r
+ return "";\r
+ }\r
+\r
+ return Encoding.UTF8.GetString(ReadBinary(length));\r
+ }\r
+\r
+ /**
+ * Read a byte[] from the wire.
+ */\r
+ public override byte[] ReadBinary()\r
+ {\r
+ int length = (int)ReadVarint32();\r
+ if (length == 0) return new byte[0];\r
+\r
+ byte[] buf = new byte[length];\r
+ trans.ReadAll(buf, 0, length);\r
+ return buf;\r
+ }\r
+\r
+ /**
+ * Read a byte[] of a known length from the wire.
+ */\r
+ private byte[] ReadBinary(int length)\r
+ {\r
+ if (length == 0) return new byte[0];\r
+\r
+ byte[] buf = new byte[length];\r
+ trans.ReadAll(buf, 0, length);\r
+ return buf;\r
+ }\r
+\r
+ //\r
+ // These methods are here for the struct to call, but don't have any wire \r
+ // encoding.\r
+ //\r
+ public override void ReadMessageEnd() { }\r
+ public override void ReadFieldEnd() { }\r
+ public override void ReadMapEnd() { }\r
+ public override void ReadListEnd() { }\r
+ public override void ReadSetEnd() { }\r
+\r
+ //\r
+ // Internal Reading methods\r
+ //\r
+\r
+ /**
+ * 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.
+ */\r
+ private uint ReadVarint32()\r
+ {\r
+ uint result = 0;\r
+ int shift = 0;\r
+ while (true)\r
+ {\r
+ byte b = ReadByte();\r
+ result |= (uint)(b & 0x7f) << shift;\r
+ if ((b & 0x80) != 0x80) break;\r
+ shift += 7;\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ private ulong ReadVarint64()\r
+ {\r
+ int shift = 0;\r
+ ulong result = 0;\r
+ while (true)\r
+ {\r
+ byte b = ReadByte();\r
+ result |= (ulong)(b & 0x7f) << shift;\r
+ if ((b & 0x80) != 0x80) break;\r
+ shift += 7;\r
+ }
+ \r
+ return result;\r
+ }\r
+\r
+ #endregion\r
+\r
+ //\r
+ // encoding helpers\r
+ //\r
+\r
+ /**
+ * Convert from zigzag int to int.
+ */\r
+ private int zigzagToInt(uint n)\r
+ {\r
+ return (int)(n >> 1) ^ (-(int)(n & 1));\r
+ }\r
+\r
+ /**
+ * Convert from zigzag long to long.
+ */\r
+ private long zigzagToLong(ulong n)\r
+ {\r
+ return (long)(n >> 1) ^ (-(long)(n & 1));\r
+ }\r
+\r
+ /**
+ * 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.
+ */\r
+ private long bytesToLong(byte[] bytes)\r
+ {\r
+ return\r
+ ((bytes[7] & 0xffL) << 56) |\r
+ ((bytes[6] & 0xffL) << 48) |\r
+ ((bytes[5] & 0xffL) << 40) |\r
+ ((bytes[4] & 0xffL) << 32) |\r
+ ((bytes[3] & 0xffL) << 24) |\r
+ ((bytes[2] & 0xffL) << 16) |\r
+ ((bytes[1] & 0xffL) << 8) |\r
+ ((bytes[0] & 0xffL));\r
+ }\r
+\r
+ //\r
+ // type testing and converting\r
+ //\r
+\r
+ private Boolean isBoolType(byte b)\r
+ {\r
+ int lowerNibble = b & 0x0f;\r
+ return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;\r
+ }\r
+\r
+ /**
+ * Given a TCompactProtocol.Types constant, convert it to its corresponding
+ * TType value.
+ */\r
+ private TType getTType(byte type)\r
+ {\r
+ switch ((byte)(type & 0x0f))\r
+ {\r
+ case Types.STOP:\r
+ return TType.Stop;\r
+ case Types.BOOLEAN_FALSE:\r
+ case Types.BOOLEAN_TRUE:\r
+ return TType.Bool;\r
+ case Types.BYTE:\r
+ return TType.Byte;\r
+ case Types.I16:\r
+ return TType.I16;\r
+ case Types.I32:\r
+ return TType.I32;\r
+ case Types.I64:\r
+ return TType.I64;\r
+ case Types.DOUBLE:\r
+ return TType.Double;\r
+ case Types.BINARY:\r
+ return TType.String;\r
+ case Types.LIST:\r
+ return TType.List;\r
+ case Types.SET:\r
+ return TType.Set;\r
+ case Types.MAP:\r
+ return TType.Map;\r
+ case Types.STRUCT:\r
+ return TType.Struct;\r
+ default:\r
+ throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));\r
+ }\r
+ }\r
+\r
+ /**
+ * Given a TType value, find the appropriate TCompactProtocol.Types constant.
+ */\r
+ private byte getCompactType(TType ttype)\r
+ {\r
+ return ttypeToCompactType[(int)ttype];\r
+ }\r
+ }\r
+}