diff options
Diffstat (limited to 'lib/csharp/src/Protocol/TCompactProtocol.cs')
-rw-r--r-- | lib/csharp/src/Protocol/TCompactProtocol.cs | 849 |
1 files changed, 0 insertions, 849 deletions
diff --git a/lib/csharp/src/Protocol/TCompactProtocol.cs b/lib/csharp/src/Protocol/TCompactProtocol.cs deleted file mode 100644 index ff673975e..000000000 --- a/lib/csharp/src/Protocol/TCompactProtocol.cs +++ /dev/null @@ -1,849 +0,0 @@ -/** - * 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. - */ - -using System; -using System.Text; -using Thrift.Transport; -using System.Collections; -using System.IO; -using System.Collections.Generic; - -namespace Thrift.Protocol -{ - public class TCompactProtocol : TProtocol - { - private static TStruct ANONYMOUS_STRUCT = new TStruct(""); - private static TField TSTOP = new TField("", TType.Stop, (short)0); - - private static byte[] ttypeToCompactType = new byte[16]; - - private const byte PROTOCOL_ID = 0x82; - private const byte VERSION = 1; - private const byte VERSION_MASK = 0x1f; // 0001 1111 - private const byte TYPE_MASK = 0xE0; // 1110 0000 - private const byte TYPE_BITS = 0x07; // 0000 0111 - private const int TYPE_SHIFT_AMOUNT = 5; - - /// <summary> - /// All of the on-wire type codes. - /// </summary> - private static class Types - { - public const byte STOP = 0x00; - public const byte BOOLEAN_TRUE = 0x01; - public const byte BOOLEAN_FALSE = 0x02; - public const byte BYTE = 0x03; - public const byte I16 = 0x04; - public const byte I32 = 0x05; - public const byte I64 = 0x06; - public const byte DOUBLE = 0x07; - public const byte BINARY = 0x08; - public const byte LIST = 0x09; - public const byte SET = 0x0A; - public const byte MAP = 0x0B; - public const byte STRUCT = 0x0C; - } - - /// <summary> - /// Used to keep track of the last field for the current and previous structs, - /// so we can do the delta stuff. - /// </summary> - private Stack<short> lastField_ = new Stack<short>(15); - - private short lastFieldId_ = 0; - - /// <summary> - /// If we encounter a boolean field begin, save the TField here so it can - /// have the value incorporated. - /// </summary> - private Nullable<TField> booleanField_; - - /// <summary> - /// If we Read a field header, and it's a boolean field, save the boolean - /// value here so that ReadBool can use it. - /// </summary> - private Nullable<Boolean> boolValue_; - - - #region CompactProtocol Factory - - public class Factory : TProtocolFactory - { - public Factory() { } - - public TProtocol GetProtocol(TTransport trans) - { - return new TCompactProtocol(trans); - } - } - - #endregion - - public TCompactProtocol(TTransport trans) - : base(trans) - { - ttypeToCompactType[(int)TType.Stop] = Types.STOP; - ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE; - ttypeToCompactType[(int)TType.Byte] = Types.BYTE; - ttypeToCompactType[(int)TType.I16] = Types.I16; - ttypeToCompactType[(int)TType.I32] = Types.I32; - ttypeToCompactType[(int)TType.I64] = Types.I64; - ttypeToCompactType[(int)TType.Double] = Types.DOUBLE; - ttypeToCompactType[(int)TType.String] = Types.BINARY; - ttypeToCompactType[(int)TType.List] = Types.LIST; - ttypeToCompactType[(int)TType.Set] = Types.SET; - ttypeToCompactType[(int)TType.Map] = Types.MAP; - ttypeToCompactType[(int)TType.Struct] = Types.STRUCT; - } - - public void reset() - { - lastField_.Clear(); - lastFieldId_ = 0; - } - - #region Write Methods - - /// <summary> - /// 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. - /// </summary> - private byte[] byteDirectBuffer = new byte[1]; - - private void WriteByteDirect(byte b) - { - byteDirectBuffer[0] = b; - trans.Write(byteDirectBuffer); - } - - /// <summary> - /// Writes a byte without any possibility of all that field header nonsense. - /// </summary> - private void WriteByteDirect(int n) - { - WriteByteDirect((byte)n); - } - - /// <summary> - /// Write an i32 as a varint. Results in 1-5 bytes on the wire. - /// TODO: make a permanent buffer like WriteVarint64? - /// </summary> - byte[] i32buf = new byte[5]; - - private void WriteVarint32(uint n) - { - 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); - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteMessageBegin(TMessage message) - { - WriteByteDirect(PROTOCOL_ID); - WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK))); - WriteVarint32((uint)message.SeqID); - WriteString(message.Name); - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteStructBegin(TStruct strct) - { - lastField_.Push(lastFieldId_); - lastFieldId_ = 0; - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteStructEnd() - { - lastFieldId_ = lastField_.Pop(); - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteFieldBegin(TField field) - { - if (field.Type == TType.Bool) - { - // we want to possibly include the value, so we'll wait. - booleanField_ = field; - } - else - { - WriteFieldBeginInternal(field, 0xFF); - } - } - - /// <summary> - /// 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. - /// </summary> - private void WriteFieldBeginInternal(TField field, byte typeOverride) - { - // short lastField = lastField_.Pop(); - - // if there's a type override, use that. - byte typeToWrite = typeOverride == 0xFF ? 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); - } - - lastFieldId_ = field.ID; - // lastField_.push(field.id); - } - - /// <summary> - /// Write the STOP symbol so we know there are no more fields in this struct. - /// </summary> - public override void WriteFieldStop() - { - WriteByteDirect(Types.STOP); - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteMapBegin(TMap map) - { - if (map.Count == 0) - { - WriteByteDirect(0); - } - else - { - WriteVarint32((uint)map.Count); - WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType)); - } - } - - /// <summary> - /// Write a list header. - /// </summary> - public override void WriteListBegin(TList list) - { - WriteCollectionBegin(list.ElementType, list.Count); - } - - /// <summary> - /// Write a set header. - /// </summary> - public override void WriteSetBegin(TSet set) - { - WriteCollectionBegin(set.ElementType, set.Count); - } - - /// <summary> - /// 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. - /// </summary> - public override void WriteBool(Boolean b) - { - if (booleanField_ != null) - { - // we haven't written the field header yet - WriteFieldBeginInternal(booleanField_.Value, 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); - } - } - - /// <summary> - /// Write a byte. Nothing to see here! - /// </summary> - public override void WriteByte(sbyte b) - { - WriteByteDirect((byte)b); - } - - /// <summary> - /// Write an I16 as a zigzag varint. - /// </summary> - public override void WriteI16(short i16) - { - WriteVarint32(intToZigZag(i16)); - } - - /// <summary> - /// Write an i32 as a zigzag varint. - /// </summary> - public override void WriteI32(int i32) - { - WriteVarint32(intToZigZag(i32)); - } - - /// <summary> - /// Write an i64 as a zigzag varint. - /// </summary> - public override void WriteI64(long i64) - { - WriteVarint64(longToZigzag(i64)); - } - - /// <summary> - /// Write a double to the wire as 8 bytes. - /// </summary> - public override void WriteDouble(double dub) - { - byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; - fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0); - trans.Write(data); - } - - /// <summary> - /// Write a string to the wire with a varint size preceding. - /// </summary> - public override void WriteString(string str) - { - byte[] bytes = UTF8Encoding.UTF8.GetBytes(str); - WriteBinary(bytes, 0, bytes.Length); - } - - /// <summary> - /// Write a byte array, using a varint for the size. - /// </summary> - public override void WriteBinary(byte[] bin) - { - WriteBinary(bin, 0, bin.Length); - } - - private void WriteBinary(byte[] buf, int offset, int length) - { - WriteVarint32((uint)length); - trans.Write(buf, offset, length); - } - - // - // These methods are called by structs, but don't actually have any wire - // output or purpose. - // - - public override void WriteMessageEnd() { } - public override void WriteMapEnd() { } - public override void WriteListEnd() { } - public override void WriteSetEnd() { } - public override void WriteFieldEnd() { } - - // - // Internal writing methods - // - - /// <summary> - /// Abstract method for writing the start of lists and sets. List and sets on - /// the wire differ only by the type indicator. - /// </summary> - protected void WriteCollectionBegin(TType elemType, int size) - { - if (size <= 14) - { - WriteByteDirect(size << 4 | getCompactType(elemType)); - } - else - { - WriteByteDirect(0xf0 | getCompactType(elemType)); - WriteVarint32((uint)size); - } - } - - /// <summary> - /// Write an i64 as a varint. Results in 1-10 bytes on the wire. - /// </summary> - byte[] varint64out = new byte[10]; - private void WriteVarint64(ulong n) - { - int idx = 0; - while (true) - { - if ((n & ~(ulong)0x7FL) == 0) - { - varint64out[idx++] = (byte)n; - break; - } - else - { - varint64out[idx++] = ((byte)((n & 0x7F) | 0x80)); - n >>= 7; - } - } - trans.Write(varint64out, 0, idx); - } - - /// <summary> - /// Convert l into a zigzag long. This allows negative numbers to be - /// represented compactly as a varint. - /// </summary> - private ulong longToZigzag(long n) - { - return (ulong)(n << 1) ^ (ulong)(n >> 63); - } - - /// <summary> - /// Convert n into a zigzag int. This allows negative numbers to be - /// represented compactly as a varint. - /// </summary> - private uint intToZigZag(int n) - { - return (uint)(n << 1) ^ (uint)(n >> 31); - } - - /// <summary> - /// Convert a long into little-endian bytes in buf starting at off and going - /// until off+7. - /// </summary> - private void fixedLongToBytes(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); - } - - #endregion - - #region ReadMethods - - /// <summary> - /// Read a message header. - /// </summary> - public override TMessage ReadMessageBegin() - { - byte protocolId = (byte)ReadByte(); - if (protocolId != PROTOCOL_ID) - { - throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X")); - } - byte versionAndType = (byte)ReadByte(); - byte version = (byte)(versionAndType & VERSION_MASK); - if (version != VERSION) - { - throw new TProtocolException("Expected version " + VERSION + " but got " + version); - } - byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS); - int seqid = (int)ReadVarint32(); - string messageName = ReadString(); - return new TMessage(messageName, (TMessageType)type, seqid); - } - - /// <summary> - /// 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. - /// </summary> - public override TStruct ReadStructBegin() - { - lastField_.Push(lastFieldId_); - lastFieldId_ = 0; - return ANONYMOUS_STRUCT; - } - - /// <summary> - /// Doesn't actually consume any wire data, just removes the last field for - /// this struct from the field stack. - /// </summary> - public override void ReadStructEnd() - { - // consume the last field we Read off the wire. - lastFieldId_ = lastField_.Pop(); - } - - /// <summary> - /// Read a field header off the wire. - /// </summary> - public override TField ReadFieldBegin() - { - byte type = (byte)ReadByte(); - - // if it's a stop, then we can return immediately, as the struct is over. - if (type == Types.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 ? true : false; - } - - // push the new field onto the field stack so we can keep the deltas going. - lastFieldId_ = field.ID; - return field; - } - - /// <summary> - /// 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. - /// </summary> - public override TMap ReadMapBegin() - { - int size = (int)ReadVarint32(); - byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte(); - return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size); - } - - /// <summary> - /// 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. - /// </summary> - public override TList ReadListBegin() - { - byte size_and_type = (byte)ReadByte(); - int size = (size_and_type >> 4) & 0x0f; - if (size == 15) - { - size = (int)ReadVarint32(); - } - TType type = getTType(size_and_type); - return new TList(type, size); - } - - /// <summary> - /// 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. - /// </summary> - public override TSet ReadSetBegin() - { - return new TSet(ReadListBegin()); - } - - /// <summary> - /// 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. - /// </summary> - public override Boolean ReadBool() - { - if (boolValue_ != null) - { - bool result = boolValue_.Value; - boolValue_ = null; - return result; - } - return ReadByte() == Types.BOOLEAN_TRUE; - } - - byte[] byteRawBuf = new byte[1]; - /// <summary> - /// Read a single byte off the wire. Nothing interesting here. - /// </summary> - public override sbyte ReadByte() - { - trans.ReadAll(byteRawBuf, 0, 1); - return (sbyte)byteRawBuf[0]; - } - - /// <summary> - /// Read an i16 from the wire as a zigzag varint. - /// </summary> - public override short ReadI16() - { - return (short)zigzagToInt(ReadVarint32()); - } - - /// <summary> - /// Read an i32 from the wire as a zigzag varint. - /// </summary> - public override int ReadI32() - { - return zigzagToInt(ReadVarint32()); - } - - /// <summary> - /// Read an i64 from the wire as a zigzag varint. - /// </summary> - public override long ReadI64() - { - return zigzagToLong(ReadVarint64()); - } - - /// <summary> - /// No magic here - just Read a double off the wire. - /// </summary> - public override double ReadDouble() - { - byte[] longBits = new byte[8]; - trans.ReadAll(longBits, 0, 8); - return BitConverter.Int64BitsToDouble(bytesToLong(longBits)); - } - - /// <summary> - /// Reads a byte[] (via ReadBinary), and then UTF-8 decodes it. - /// </summary> - public override string ReadString() - { - int length = (int)ReadVarint32(); - - if (length == 0) - { - return ""; - } - - return Encoding.UTF8.GetString(ReadBinary(length)); - } - - /// <summary> - /// Read a byte[] from the wire. - /// </summary> - public override byte[] ReadBinary() - { - int length = (int)ReadVarint32(); - if (length == 0) return new byte[0]; - - byte[] buf = new byte[length]; - trans.ReadAll(buf, 0, length); - return buf; - } - - /// <summary> - /// Read a byte[] of a known length from the wire. - /// </summary> - private byte[] ReadBinary(int length) - { - if (length == 0) return new byte[0]; - - byte[] buf = new byte[length]; - trans.ReadAll(buf, 0, length); - return buf; - } - - // - // These methods are here for the struct to call, but don't have any wire - // encoding. - // - public override void ReadMessageEnd() { } - public override void ReadFieldEnd() { } - public override void ReadMapEnd() { } - public override void ReadListEnd() { } - public override void ReadSetEnd() { } - - // - // Internal Reading methods - // - - /// <summary> - /// 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. - /// </summary> - private uint ReadVarint32() - { - uint result = 0; - int shift = 0; - while (true) - { - byte b = (byte)ReadByte(); - result |= (uint)(b & 0x7f) << shift; - if ((b & 0x80) != 0x80) break; - shift += 7; - } - return result; - } - - /// <summary> - /// 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. - /// </summary> - private ulong ReadVarint64() - { - int shift = 0; - ulong result = 0; - while (true) - { - byte b = (byte)ReadByte(); - result |= (ulong)(b & 0x7f) << shift; - if ((b & 0x80) != 0x80) break; - shift += 7; - } - - return result; - } - - #endregion - - // - // encoding helpers - // - - /// <summary> - /// Convert from zigzag int to int. - /// </summary> - private int zigzagToInt(uint n) - { - return (int)(n >> 1) ^ (-(int)(n & 1)); - } - - /// <summary> - /// Convert from zigzag long to long. - /// </summary> - private long zigzagToLong(ulong n) - { - return (long)(n >> 1) ^ (-(long)(n & 1)); - } - - /// <summary> - /// 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. - /// </summary> - private long bytesToLong(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 - // - - private Boolean isBoolType(byte b) - { - int lowerNibble = b & 0x0f; - return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE; - } - - /// <summary> - /// Given a TCompactProtocol.Types constant, convert it to its corresponding - /// TType value. - /// </summary> - private TType getTType(byte type) - { - switch ((byte)(type & 0x0f)) - { - case Types.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: - throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f)); - } - } - - /// <summary> - /// Given a TType value, find the appropriate TCompactProtocol.Types constant. - /// </summary> - private byte getCompactType(TType ttype) - { - return ttypeToCompactType[(int)ttype]; - } - } -} |