THRIFT-2933: Repairs incorrect double byte order in Node compact proto
Client Nodejs
Patch: Dan Heller
diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js
index 782b767..8e0dbd1 100644
--- a/lib/nodejs/lib/thrift/protocol.js
+++ b/lib/nodejs/lib/thrift/protocol.js
@@ -38,6 +38,14 @@
VERSION_1 = -2147418112, // 0x80010000
TYPE_MASK = 0x000000ff;
+var POW_8 = Math.pow(2, 8);
+var POW_24 = Math.pow(2, 24);
+var POW_32 = Math.pow(2, 32);
+var POW_40 = Math.pow(2, 40);
+var POW_48 = Math.pow(2, 48);
+var POW_52 = Math.pow(2, 52);
+var POW_1022 = Math.pow(2, 1022);
+
var TBinaryProtocol = exports.TBinaryProtocol = function(trans, strictRead, strictWrite) {
this.trans = trans;
this.strictRead = (strictRead !== undefined ? strictRead : false);
@@ -678,8 +686,67 @@
this.writeVarint64(this.i64ToZigzag(i64));
};
-TCompactProtocol.prototype.writeDouble = function(dub) {
- this.trans.write(binary.writeDouble(new Buffer(8), dub));
+// Little-endian, unlike TBinaryProtocol
+TCompactProtocol.prototype.writeDouble = function(v) {
+ var buff = new Buffer(8);
+ var m, e, c;
+
+ buff[7] = (v < 0 ? 0x80 : 0x00);
+
+ v = Math.abs(v);
+ if (v !== v) {
+ // NaN, use QNaN IEEE format
+ m = 2251799813685248;
+ e = 2047;
+ } else if (v === Infinity) {
+ m = 0;
+ e = 2047;
+ } else {
+ e = Math.floor(Math.log(v) / Math.LN2);
+ c = Math.pow(2, -e);
+ if (v * c < 1) {
+ e--;
+ c *= 2;
+ }
+
+ if (e + 1023 >= 2047)
+ {
+ // Overflow
+ m = 0;
+ e = 2047;
+ }
+ else if (e + 1023 >= 1)
+ {
+ // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow
+ m = (v*c-1) * POW_52;
+ e += 1023;
+ }
+ else
+ {
+ // Denormalized - also catches the '0' case, somewhat by chance
+ m = (v * POW_1022) * POW_52;
+ e = 0;
+ }
+ }
+
+ buff[6] = (e << 4) & 0xf0;
+ buff[7] |= (e >> 4) & 0x7f;
+
+ buff[0] = m & 0xff;
+ m = Math.floor(m / POW_8);
+ buff[1] = m & 0xff;
+ m = Math.floor(m / POW_8);
+ buff[2] = m & 0xff;
+ m = Math.floor(m / POW_8);
+ buff[3] = m & 0xff;
+ m >>= 8;
+ buff[4] = m & 0xff;
+ m >>= 8;
+ buff[5] = m & 0xff;
+ m >>= 8;
+ buff[6] |= m & 0x0f;
+
+ this.trans.write(buff);
};
TCompactProtocol.prototype.writeString = function(arg) {
@@ -968,8 +1035,39 @@
return this.zigzagToI64(this.readVarint64());
};
+// Little-endian, unlike TBinaryProtocol
TCompactProtocol.prototype.readDouble = function() {
- return this.trans.readDouble();
+ var buff = this.trans.read(8);
+ var off = 0;
+
+ var signed = buff[off + 7] & 0x80;
+ var e = (buff[off+6] & 0xF0) >> 4;
+ e += (buff[off+7] & 0x7F) << 4;
+
+ var m = buff[off];
+ m += buff[off+1] << 8;
+ m += buff[off+2] << 16;
+ m += buff[off+3] * POW_24;
+ m += buff[off+4] * POW_32;
+ m += buff[off+5] * POW_40;
+ m += (buff[off+6] & 0x0F) * POW_48;
+
+ switch (e) {
+ case 0:
+ e = -1022;
+ break;
+ case 2047:
+ return m ? NaN : (signed ? -Infinity : Infinity);
+ default:
+ m += POW_52;
+ e -= 1023;
+ }
+
+ if (signed) {
+ m *= -1;
+ }
+
+ return m * Math.pow(2, e - 52);
};
TCompactProtocol.prototype.readBinary = function() {