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() {