summaryrefslogtreecommitdiff
path: root/lib/haxe
diff options
context:
space:
mode:
authorJens Geyer <jensg@apache.org>2015-03-02 23:37:15 +0100
committerJens Geyer <jensg@apache.org>2015-03-05 23:43:23 +0100
commit426ab8680126ac914c566adbcda3d6e93d57df64 (patch)
treec168201bc2b7a232688865fbdbb306ac5e3b51ea /lib/haxe
parent6f7399b355b77b3e6dc32ffa475d42493afe2d90 (diff)
downloadthrift-426ab8680126ac914c566adbcda3d6e93d57df64.tar.gz
THRIFT-3022 Compact protocol for Haxe
Client: Haxe Patch: Jens Geyer This closes #388
Diffstat (limited to 'lib/haxe')
-rw-r--r--lib/haxe/src/org/apache/thrift/helper/BitConverter.hx159
-rw-r--r--lib/haxe/src/org/apache/thrift/helper/ZigZag.hx128
-rw-r--r--lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx730
-rw-r--r--lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx40
4 files changed, 1057 insertions, 0 deletions
diff --git a/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
new file mode 100644
index 000000000..7f7c8f794
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+package org.apache.thrift.helper;
+
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+
+class BitConverter {
+
+ public static function DoubleToInt64Bits( db : Float) : Int64 {
+ var buf = new BytesBuffer();
+ buf.addDouble( db);
+ return bytesToLong( buf.getBytes());
+ }
+
+
+ public static function Int64BitsToDouble( i64 : Int64) : Float {
+ var buf = new BytesBuffer();
+ buf.add( fixedLongToBytes( i64));
+ return buf.getBytes().getDouble(0);
+ }
+
+
+
+ /**
+ * Convert a long into little-endian bytes in buf starting at off and going
+ * until off+7.
+ */
+ public static function fixedLongToBytes( n : Int64) : Bytes {
+ var buf = Bytes.alloc(8);
+ buf.set( 0, Int64.getLow( Int64.and( n, Int64.make(0, 0xff))));
+ buf.set( 1, Int64.getLow( Int64.and( Int64.shr( n, 8), Int64.make(0, 0xff))));
+ buf.set( 2, Int64.getLow( Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff))));
+ buf.set( 3, Int64.getLow( Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff))));
+ buf.set( 4, Int64.getLow( Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff))));
+ buf.set( 5, Int64.getLow( Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff))));
+ buf.set( 6, Int64.getLow( Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff))));
+ buf.set( 7, Int64.getLow( Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff))));
+ return buf;
+ }
+
+ /**
+ * 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.
+ */
+ public static function bytesToLong( bytes : Bytes) : Int64 {
+ var result : Int64 = Int64.make(0, 0);
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(7)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(6)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(5)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(4)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(3)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(2)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(1)));
+ result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(0)));
+ return result;
+ }
+
+
+ #if debug
+ private static function TestBTL( test : Int64) : Void {
+ var buf : Bytes = fixedLongToBytes( test);
+ var erg = bytesToLong(buf);
+ if ( Int64.compare( erg, test) != 0)
+ throw 'BitConverter.bytesToLongTest($test) failed: $erg';
+ }
+ #end
+
+
+ #if debug
+ private static function TestPair( a : Float, b : Int64) : Void {
+ var bx = DoubleToInt64Bits(a);
+ if ( Int64.compare( bx, b) != 0)
+ throw 'BitConverter.TestPair: DoubleToInt64Bits($a): expected $b, got $bx';
+ var ax = Int64BitsToDouble(b);
+ if( ax != a)
+ throw 'BitConverter.TestPair: Int64BitsToDouble($b: expected $a, got $ax';
+ }
+ #end
+
+
+ #if debug
+ public static function UnitTest() : Void {
+
+ // bytesToLong()
+ var i : Int;
+ TestBTL( Int64.make(0,0));
+ for ( i in 0 ... 62) {
+ TestBTL( Int64.shl( Int64.make(0,1), i));
+ TestBTL( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+ }
+ TestBTL( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+ TestBTL( Int64.make(cast(0x80000000,Int),0x00000000));
+
+ // DoubleToInt64Bits;
+ TestPair( 1.0000000000000000E+000, Int64.make(cast(0x3FF00000,Int),cast(0x00000000,Int)));
+ TestPair( 1.5000000000000000E+001, Int64.make(cast(0x402E0000,Int),cast(0x00000000,Int)));
+ TestPair( 2.5500000000000000E+002, Int64.make(cast(0x406FE000,Int),cast(0x00000000,Int)));
+ TestPair( 4.2949672950000000E+009, Int64.make(cast(0x41EFFFFF,Int),cast(0xFFE00000,Int)));
+ TestPair( 3.9062500000000000E-003, Int64.make(cast(0x3F700000,Int),cast(0x00000000,Int)));
+ TestPair( 2.3283064365386963E-010, Int64.make(cast(0x3DF00000,Int),cast(0x00000000,Int)));
+ TestPair( 1.2345678901230000E-300, Int64.make(cast(0x01AA74FE,Int),cast(0x1C1E7E45,Int)));
+ TestPair( 1.2345678901234500E-150, Int64.make(cast(0x20D02A36,Int),cast(0x586DB4BB,Int)));
+ TestPair( 1.2345678901234565E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FA,Int)));
+ TestPair( 1.2345678901234567E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FB,Int)));
+ TestPair( 1.2345678901234569E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FC,Int)));
+ TestPair( 1.2345678901234569E+150, Int64.make(cast(0x5F182344,Int),cast(0xCD3CDF9F,Int)));
+ TestPair( 1.2345678901234569E+300, Int64.make(cast(0x7E3D7EE8,Int),cast(0xBCBBD352,Int)));
+ TestPair( -1.7976931348623157E+308, Int64.make(cast(0xFFEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+ TestPair( 1.7976931348623157E+308, Int64.make(cast(0x7FEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+ TestPair( 4.9406564584124654E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+ TestPair( 0.0000000000000000E+000, Int64.make(cast(0x00000000,Int),cast(0x00000000,Int)));
+ TestPair( 4.94065645841247E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+ TestPair( 3.2378592100206092E-319, Int64.make(cast(0x00000000,Int),cast(0x0000FFFF,Int)));
+ TestPair( 1.3906711615669959E-309, Int64.make(cast(0x0000FFFF,Int),cast(0xFFFFFFFF,Int)));
+ TestPair( Math.NEGATIVE_INFINITY, Int64.make(cast(0xFFF00000,Int),cast(0x00000000,Int)));
+ TestPair( Math.POSITIVE_INFINITY, Int64.make(cast(0x7FF00000,Int),cast(0x00000000,Int)));
+
+ // NaN is special
+ var i64nan = DoubleToInt64Bits( Math.NaN);
+ var i64cmp = Int64.make(cast(0xFFF80000, Int), cast(0x00000000, Int));
+ if ( ! Math.isNaN( Int64BitsToDouble( i64cmp)))
+ throw 'BitConverter NaN-Test #1: expected NaN';
+
+ // For doubles, a quiet NaN is a bit pattern
+ // between 7FF8000000000000 and 7FFFFFFFFFFFFFFF
+ // or FFF8000000000000 and FFFFFFFFFFFFFFFF
+ var min1 = Int64.make( cast(0x7FF80000, Int), cast(0x00000000, Int));
+ var max1 = Int64.make( cast(0x7FFFFFFF, Int), cast(0xFFFFFFFF, Int));
+ var min2 = Int64.make( cast(0xFFF80000, Int), cast(0x00000000, Int));
+ var max2 = Int64.make( cast(0xFFFFFFFF, Int), cast(0xFFFFFFFF, Int));
+ var ok1 = (Int64.compare( min1, i64nan) <= 0) && (Int64.compare( i64nan, max1) <= 0);
+ var ok2 = (Int64.compare( min2, i64nan) <= 0) && (Int64.compare( i64nan, max2) <= 0);
+ if( ! (ok1 || ok2))
+ throw 'BitConverter NaN-Test #2: failed';
+ }
+ #end
+
+}
+ \ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
new file mode 100644
index 000000000..862060d8d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+package org.apache.thrift.helper;
+
+import haxe.Int64;
+
+class ZigZag {
+
+ /**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+ public static function FromInt( n : Int) : UInt {
+ return cast(n << 1,UInt) ^ cast(n >> 31,UInt);
+ }
+
+
+ /**
+ * Convert from zigzag int to int.
+ */
+ public static function ToInt( n : UInt) : Int {
+ return (0x7FFFFFFF & cast(n >> 1,Int)) ^ (-cast(n & 1,Int));
+ }
+
+
+ /**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+ public static function FromLong( n : Int64) : Int64 {
+ return Int64.xor( Int64.shl(n, 1), Int64.shr(n, 63));
+ }
+
+
+ /**
+ * Convert from zigzag long to long.
+ */
+ public static function ToLong( n : Int64) : Int64 {
+ return Int64.xor(
+ Int64.and(
+ Int64.shr(n, 1),
+ Int64.make(0x7FFFFFFF, 0xFFFFFFFF)),
+ Int64.sub(
+ Int64.make(0, 0),
+ Int64.and(n, Int64.make(0,1))));
+ }
+
+
+ #if debug
+ private static function Test32( test : Int) : Void {
+ var a : UInt = ZigZag.FromInt( test);
+ var b : Int = ZigZag.ToInt(a);
+ if( test != b)
+ throw 'ZigZag.Test32($test) failed: a = $a, b = $b';
+ }
+ #end
+
+
+
+ #if debug
+ private static function Test64( test : haxe.Int64) : Void {
+ var a : Int64 = ZigZag.FromLong( test);
+ var b : Int64 = ZigZag.ToLong(a);
+ if( Int64.compare( test, b) != 0)
+ throw 'ZigZag.Test64($test) failed: a = $a, b = $b';
+ }
+ #end
+
+
+ #if debug
+ public static function UnitTest() : Void {
+ var u1 : UInt = 0xFFFFFFFE;
+ var u2 : UInt = 0xFFFFFFFF;
+
+ // protobuf testcases
+ if( FromInt(0) != 0) throw 'pb #1 to ZigZag';
+ if( FromInt(-1) != 1) throw 'pb #2 to ZigZag';
+ if( FromInt(1) != 2) throw 'pb #3 to ZigZag';
+ if( FromInt(-2) != 3) throw 'pb #4 to ZigZag';
+ if( FromInt(2147483647) != u1) throw 'pb #5 to ZigZag';
+ if( FromInt(-2147483648) != u2) throw 'pb #6 to ZigZag';
+
+ // protobuf testcases
+ if( ToInt(0) != 0) throw 'pb #1 from ZigZag';
+ if( ToInt(1) != -1) throw 'pb #2 from ZigZag';
+ if( ToInt(2) != 1) throw 'pb #3 from ZigZag';
+ if( ToInt(3) != -2) throw 'pb #4 from ZigZag';
+ if( ToInt(u1) != 2147483647) throw 'pb #5 from ZigZag, got ${ToInt(u1)}';
+ if( ToInt(u2) != -2147483648) throw 'pb #6 from ZigZag, got ${ToInt(u2)}';
+
+ // back and forth 32
+ Test32( 0);
+ for( i in 0 ... 30) {
+ Test32( 1 << i);
+ Test32( -(1 << i));
+ }
+ Test32( 0x7FFFFFFF);
+ Test32( cast(0x80000000,Int));
+
+ // back and forth 64
+ Test64( Int64.make(0,0));
+ for( i in 0 ... 62) {
+ Test64( Int64.shl( Int64.make(0,1), i));
+ Test64( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+ }
+ Test64( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+ Test64( Int64.make(cast(0x80000000,Int),0x00000000));
+ }
+ #end
+}
+ \ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
new file mode 100644
index 000000000..d08a6d0bc
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
@@ -0,0 +1,730 @@
+/**
+ * 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.
+ */
+
+package org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.ds.GenericStack;
+import haxe.Int32;
+import haxe.Int64;
+import haxe.Utf8;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.helper.ZigZag;
+import org.apache.thrift.helper.BitConverter;
+
+
+/**
+ * All of the on-wire type codes.
+ */
+class TCompactTypes {
+ public static inline var STOP = 0x00;
+ public static inline var BOOLEAN_TRUE = 0x01;
+ public static inline var BOOLEAN_FALSE = 0x02;
+ public static inline var BYTE = 0x03;
+ public static inline var I16 = 0x04;
+ public static inline var I32 = 0x05;
+ public static inline var I64 = 0x06;
+ public static inline var DOUBLE = 0x07;
+ public static inline var BINARY = 0x08;
+ public static inline var LIST = 0x09;
+ public static inline var SET = 0x0A;
+ public static inline var MAP = 0x0B;
+ public static inline var STRUCT = 0x0C;
+}
+
+/**
+* Binary protocol implementation for thrift.
+*/
+class TCompactProtocol implements TProtocol {
+
+ private static var ANONYMOUS_STRUCT : TStruct = new TStruct("");
+ private static var TSTOP : TField = new TField("", TType.STOP, 0);
+
+ private static inline var PROTOCOL_ID : Int = 0x82;
+ private static inline var VERSION : Int = 1;
+ private static inline var VERSION_MASK : Int = 0x1f; // 0001 1111
+ private static inline var TYPE_MASK : Int = 0xE0; // 1110 0000
+ private static inline var TYPE_BITS : Int = 0x07; // 0000 0111
+ private static inline var TYPE_SHIFT_AMOUNT : Int = 5;
+
+
+ private static var ttypeToCompactType = [
+ TType.STOP => TCompactTypes.STOP,
+ TType.BOOL => TCompactTypes.BOOLEAN_TRUE,
+ TType.BYTE => TCompactTypes.BYTE,
+ TType.DOUBLE => TCompactTypes.DOUBLE,
+ TType.I16 => TCompactTypes.I16,
+ TType.I32 => TCompactTypes.I32,
+ TType.I64 => TCompactTypes.I64,
+ TType.STRING => TCompactTypes.BINARY,
+ TType.STRUCT => TCompactTypes.STRUCT,
+ TType.MAP => TCompactTypes.MAP,
+ TType.SET => TCompactTypes.SET,
+ TType.LIST => TCompactTypes.LIST
+ ];
+
+ private static var tcompactTypeToType = [
+ TCompactTypes.STOP => TType.STOP,
+ TCompactTypes.BOOLEAN_TRUE => TType.BOOL,
+ TCompactTypes.BOOLEAN_FALSE => TType.BOOL,
+ TCompactTypes.BYTE => TType.BYTE,
+ TCompactTypes.I16 => TType.I16,
+ TCompactTypes.I32 => TType.I32,
+ TCompactTypes.I64 => TType.I64,
+ TCompactTypes.DOUBLE => TType.DOUBLE,
+ TCompactTypes.BINARY => TType.STRING,
+ TCompactTypes.LIST => TType.LIST,
+ TCompactTypes.SET => TType.SET,
+ TCompactTypes.MAP => TType.MAP,
+ TCompactTypes.STRUCT => TType.STRUCT
+ ];
+
+
+ /**
+ * Used to keep track of the last field for the current and previous structs,
+ * so we can do the delta stuff.
+ */
+ private var lastField_ : GenericStack<Int> = new GenericStack<Int>();
+ private var lastFieldId_ : Int = 0;
+
+ /**
+ * If we encounter a boolean field begin, save the TField here so it can
+ * have the value incorporated.
+ */
+ private var booleanField_ : Null<TField>;
+
+ /**
+ * If we Read a field header, and it's a boolean field, save the boolean
+ * value here so that ReadBool can use it.
+ */
+ private var boolValue_ : Null<Bool>;
+
+
+ // whether the underlying system holds Strings as UTF-8
+ // http://old.haxe.org/manual/encoding
+ private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш");
+
+ // the transport used
+ public var trans(default,null) : TTransport;
+
+
+ // TCompactProtocol Constructor
+ public function new( trans : TTransport) {
+ this.trans = trans;
+ }
+
+ public function getTransport() : TTransport {
+ return trans;
+ }
+
+
+ public function Reset() : Void{
+ while ( ! lastField_.isEmpty()) {
+ lastField_.pop();
+ }
+ lastFieldId_ = 0;
+ }
+
+
+ /**
+ * 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.
+ */
+ private function WriteByteDirect( b : Int) : Void {
+ var buf = Bytes.alloc(1);
+ buf.set( 0, b);
+ trans.write( buf, 0, 1);
+ }
+
+ /**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ */
+ private function WriteVarint32( n : UInt) : Void {
+ var i32buf = new BytesBuffer();
+ while (true)
+ {
+ if ((n & ~0x7F) == 0)
+ {
+ i32buf.addByte( n & 0xFF);
+ break;
+ }
+ else
+ {
+ i32buf.addByte( (n & 0x7F) | 0x80);
+ n >>= 7;
+ }
+ }
+
+ var tmp = i32buf.getBytes();
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ /**
+ * 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.
+ */
+ public function writeMessageBegin( message : TMessage) : Void {
+ Reset();
+
+ var versionAndType : Int = (VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
+ WriteByteDirect( PROTOCOL_ID);
+ WriteByteDirect( versionAndType);
+ WriteVarint32( cast( message.seqid, UInt));
+ 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.
+ */
+ public function writeStructBegin(struct:TStruct) : Void {
+ lastField_.add( 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.
+ */
+ public function writeStructEnd() : Void {
+ 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.
+ */
+ public function writeFieldBegin(field:TField) : Void {
+ if (field.type == TType.BOOL)
+ booleanField_ = field; // we want to possibly include the value, so we'll wait.
+ else
+ WriteFieldBeginInternal(field, 0xFF);
+ }
+
+ /**
+ * 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.
+ */
+ private function WriteFieldBeginInternal( field : TField, typeOverride : Int) : Void {
+ // if there's a type override, use that.
+ var typeToWrite : Int;
+ if ( typeOverride == 0xFF)
+ typeToWrite = getCompactType( field.type);
+ else
+ typeToWrite = 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;
+ }
+
+ /**
+ * Write the STOP symbol so we know there are no more fields in this struct.
+ */
+ public function writeFieldStop() : Void {
+ WriteByteDirect( cast(TCompactTypes.STOP, Int));
+ }
+
+ /**
+ * 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.
+ */
+ public function writeMapBegin(map:TMap) : Void {
+ if (map.size == 0)
+ {
+ WriteByteDirect(0);
+ }
+ else
+ {
+ var kvtype = (getCompactType(map.keyType) << 4) | getCompactType(map.valueType);
+ WriteVarint32( cast( map.size, UInt));
+ WriteByteDirect( kvtype);
+ }
+ }
+
+ /**
+ * Write a list header.
+ */
+ public function writeListBegin( list : TList) : Void {
+ WriteCollectionBegin( list.elemType, list.size);
+ }
+
+ /**
+ * Write a set header.
+ */
+ public function writeSetBegin( set : TSet) : Void {
+ 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.
+ */
+ public function writeBool(b : Bool) : Void {
+ var bct : Int = b ? TCompactTypes.BOOLEAN_TRUE : TCompactTypes.BOOLEAN_FALSE;
+
+ if (booleanField_ != null)
+ {
+ // we haven't written the field header yet
+ WriteFieldBeginInternal( booleanField_, bct);
+ booleanField_ = null;
+ }
+ else
+ {
+ // we're not part of a field, so just Write the value.
+ WriteByteDirect( bct);
+ }
+ }
+
+ /**
+ * Write a byte. Nothing to see here!
+ */
+ public function writeByte( b : Int) : Void {
+ WriteByteDirect( b);
+ }
+
+ /**
+ * Write an I16 as a zigzag varint.
+ */
+ public function writeI16( i16 : Int) : Void {
+ WriteVarint32( ZigZag.FromInt( i16));
+ }
+
+ /**
+ * Write an i32 as a zigzag varint.
+ */
+ public function writeI32( i32 : Int) : Void {
+ WriteVarint32( ZigZag.FromInt( i32));
+ }
+
+ /**
+ * Write an i64 as a zigzag varint.
+ */
+ public function writeI64( i64 : haxe.Int64) : Void {
+ WriteVarint64( ZigZag.FromLong( i64));
+ }
+
+ /**
+ * Write a double to the wire as 8 bytes.
+ */
+ public function writeDouble( dub : Float) : Void {
+ var data = BitConverter.fixedLongToBytes( BitConverter.DoubleToInt64Bits(dub));
+ trans.write( data, 0, data.length);
+ }
+
+ /**
+ * Write a string to the wire with a varint size preceding.
+ */
+ public function writeString(str : String) : Void {
+ var buf = new BytesBuffer();
+ if( utf8Strings)
+ buf.addString( str); // no need to encode on UTF8 targets, the string is just fine
+ else
+ buf.addString( Utf8.encode( str));
+ var tmp = buf.getBytes();
+ writeBinary( tmp);
+ }
+
+ /**
+ * Write a byte array, using a varint for the size.
+ */
+ public function writeBinary( bin : Bytes) : Void {
+ WriteVarint32( cast(bin.length,UInt));
+ trans.write( bin, 0, bin.length);
+ }
+
+
+ // These methods are called by structs, but don't actually have any wire
+ // output or purpose.
+ public function writeMessageEnd() : Void { }
+ public function writeMapEnd() : Void { }
+ public function writeListEnd() : Void { }
+ public function writeSetEnd() : Void { }
+ public function writeFieldEnd() : Void { }
+
+ //
+ // Internal writing methods
+ //
+
+ /**
+ * Abstract method for writing the start of lists and sets. List and sets on
+ * the wire differ only by the type indicator.
+ */
+ private function WriteCollectionBegin( elemType : Int, size : Int) : Void {
+ if (size <= 14) {
+ WriteByteDirect( size << 4 | getCompactType(elemType));
+ }
+ else {
+ WriteByteDirect( 0xf0 | getCompactType(elemType));
+ WriteVarint32( cast(size, UInt));
+ }
+ }
+
+ /**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */
+ private function WriteVarint64(n : haxe.Int64) : Void {
+ var varint64out = new BytesBuffer();
+ while (true)
+ {
+ if( Int64.isZero( Int64.and( n, Int64.neg(Int64.make(0,0x7F)))))
+ {
+ varint64out.addByte( Int64.getLow(n));
+ break;
+ }
+ else
+ {
+ varint64out.addByte( (Int64.getLow(n) & 0x7F) | 0x80);
+ n = Int64.shr( n, 7);
+ n = Int64.and( n, Int64.make(0x01FFFFFF,0xFFFFFFFF)); // clean out the shifted 7 bits
+ }
+ }
+ var tmp = varint64out.getBytes();
+ trans.write( tmp, 0, tmp.length);
+ }
+
+
+ /**
+ * Read a message header.
+ */
+ public function readMessageBegin():TMessage {
+ Reset();
+
+ var protocolId : Int = readByte();
+ if (protocolId != PROTOCOL_ID) {
+ throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected protocol id " + StringTools.hex(PROTOCOL_ID,2) + " but got " + StringTools.hex(protocolId));
+ }
+
+ var versionAndType : Int = readByte();
+ var version : Int = (versionAndType & VERSION_MASK);
+ if (version != VERSION) {
+ throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected version " + VERSION + " but got " + version);
+ }
+
+ var type : Int = ((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+ var seqid : Int = cast( ReadVarint32(), Int);
+ var msgNm : String = readString();
+ return new TMessage( msgNm, 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 function readStructBegin():TStruct {
+ lastField_.add(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.
+ */
+ public function readStructEnd() : Void {
+ // consume the last field we Read off the wire.
+ lastFieldId_ = lastField_.pop();
+ }
+
+ /**
+ * Read a field header off the wire.
+ */
+ public function readFieldBegin() : TField {
+ var type : Int = readByte();
+
+ // if it's a stop, then we can return immediately, as the struct is over.
+ if (type == cast(TCompactTypes.STOP,Int)) {
+ return TSTOP;
+ }
+
+ var fieldId : Int;
+
+ // mask off the 4 MSB of the type header. it could contain a field id delta.
+ var modifier : Int = ((type & 0xf0) >> 4);
+ if (modifier == 0)
+ fieldId = readI16(); // not a delta. look ahead for the zigzag varint field id.
+ else
+ fieldId = lastFieldId_ + modifier; // add the delta to the last Read field id.
+
+ var field : TField = new TField( "", cast(getTType(type & 0x0f),Int), 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_ = ((type & 0x0f) == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+ }
+
+ // 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 function readMapBegin() : TMap {
+ var size : Int = cast( ReadVarint32(), Int);
+ var keyAndValueType : Int = ((size == 0) ? 0 : readByte());
+ var key : Int = cast( getTType( (keyAndValueType & 0xF0) >> 4), Int);
+ var val : Int = cast( getTType( keyAndValueType & 0x0F), Int);
+ return new TMap( key, val, 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 function readListBegin():TList {
+ var size_and_type : Int = readByte();
+
+ var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+ if (size == 15) {
+ size = cast( ReadVarint32(), Int);
+ }
+
+ var type = getTType(size_and_type);
+ return new 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 function readSetBegin() : TSet {
+ var size_and_type : Int = readByte();
+
+ var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+ if (size == 15) {
+ size = cast( ReadVarint32(), Int);
+ }
+
+ var type = getTType(size_and_type);
+ return new TSet( type, size);
+ }
+
+ /**
+ * 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.
+ */
+ public function readBool() : Bool {
+ if (boolValue_ != null) {
+ var result : Bool = boolValue_;
+ boolValue_ = null;
+ return result;
+ }
+
+ return (readByte() == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+ }
+
+ /**
+ * Read a single byte off the wire. Nothing interesting here.
+ */
+ public function readByte() : Int {
+ var byteRawBuf = new BytesBuffer();
+ trans.readAll( byteRawBuf, 0, 1);
+ return byteRawBuf.getBytes().get(0);
+ }
+
+ /**
+ * Read an i16 from the wire as a zigzag varint.
+ */
+ public function readI16() : Int {
+ return ZigZag.ToInt( ReadVarint32());
+ }
+
+ /**
+ * Read an i32 from the wire as a zigzag varint.
+ */
+ public function readI32() : Int {
+ return ZigZag.ToInt( ReadVarint32());
+ }
+
+ /**
+ * Read an i64 from the wire as a zigzag varint.
+ */
+ public function readI64() : haxe.Int64 {
+ return ZigZag.ToLong( ReadVarint64());
+ }
+
+ /**
+ * No magic here - just Read a double off the wire.
+ */
+ public function readDouble():Float {
+ var longBits = new BytesBuffer();
+ trans.readAll( longBits, 0, 8);
+ return BitConverter.Int64BitsToDouble( BitConverter.bytesToLong( longBits.getBytes()));
+ }
+
+ /**
+ * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+ */
+ public function readString() : String {
+ var length : Int = cast( ReadVarint32(), Int);
+
+ if (length == 0) {
+ return "";
+ }
+
+ var buf = new BytesBuffer();
+ trans.readAll( buf, 0, length);
+
+ length = buf.length;
+ var inp = new BytesInput( buf.getBytes());
+ var str = inp.readString( length);
+ if( utf8Strings)
+ return str; // no need to decode on UTF8 targets, the string is just fine
+ else
+ return Utf8.decode( str);
+ }
+
+ /**
+ * Read a byte[] from the wire.
+ */
+ public function readBinary() : Bytes {
+ var length : Int = cast( ReadVarint32(), Int);
+ if (length == 0) {
+ return Bytes.alloc(0);
+ }
+
+ var buf = new BytesBuffer();
+ trans.readAll( buf, 0, length);
+ return buf.getBytes();
+ }
+
+
+ // These methods are here for the struct to call, but don't have any wire
+ // encoding.
+ public function readMessageEnd() : Void { }
+ public function readFieldEnd() : Void { }
+ public function readMapEnd() : Void { }
+ public function readListEnd() : Void { }
+ public function readSetEnd() : Void { }
+
+ //
+ // 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.
+ */
+ private function ReadVarint32() : UInt {
+ var result : UInt = 0;
+ var shift : Int = 0;
+ while (true) {
+ var b : Int = readByte();
+ result |= cast((b & 0x7f) << shift, UInt);
+ 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.
+ */
+ private function ReadVarint64() : Int64 {
+ var shift : Int = 0;
+ var result : Int64 = Int64.make(0,0);
+ while (true) {
+ var b : Int = readByte();
+ result = Int64.or( result, Int64.shl( Int64.make(0,b & 0x7f), shift));
+ if ((b & 0x80) != 0x80) {
+ break;
+ }
+ shift += 7;
+ }
+
+ return result;
+ }
+
+
+ //
+ // type testing and converting
+ //
+
+ private function isBoolType( b : Int) : Bool {
+ var lowerNibble : Int = b & 0x0f;
+ switch(lowerNibble)
+ {
+ case TCompactTypes.BOOLEAN_TRUE: return true;
+ case TCompactTypes.BOOLEAN_FALSE: return true;
+ default: return false;
+ }
+ }
+
+
+ /**
+ * Given a TCompactProtocol.TCompactTypes constant, convert it to its corresponding
+ * TType value.
+ */
+ private function getTType( type : Int) : Int {
+ try
+ {
+ return tcompactTypeToType[type];
+ throw "fuck";
+ }
+ catch ( e : Dynamic)
+ {
+ var tt : Int = (type & 0x0f);
+ throw new TProtocolException( TProtocolException.UNKNOWN, 'don\'t know what type: $tt ($e)');
+ }
+ }
+
+ /**
+ * Given a TType value, find the appropriate TCompactProtocol.TCompactTypes constant.
+ */
+ private function getCompactType( ttype : Int) : Int
+ {
+ return cast( ttypeToCompactType[ttype], Int);
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
new file mode 100644
index 000000000..c5673b40c
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* Compact Protocol Factory
+*/
+class TCompactProtocolFactory implements TProtocolFactory {
+
+ public function new() {
+ }
+
+ public function getProtocol( trans : TTransport) : TProtocol {
+ return new TCompactProtocol( trans);
+ }
+}
+
+
+
+ \ No newline at end of file