Skip to content

Commit

Permalink
Swapped to BinaryParser for packing/unpacking doubles
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Whitlock committed Jul 27, 2010
1 parent e3e85b8 commit 9900fb3
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 10 deletions.
134 changes: 134 additions & 0 deletions node-amf/bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/**
* Binary tools for node-amf
*/

var BinaryParser;

exports.parser = function( bigEndian, allowExceptions ){
return new BinaryParser( bigEndian, allowExceptions );
}






// code below copied asis from http://jsfromhell.com/


//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/binary-parser [rev. #1]

BinaryParser = function(bigEndian, allowExceptions){
this.bigEndian = bigEndian, this.allowExceptions = allowExceptions;
};
with({p: BinaryParser.prototype}){
p.encodeFloat = function(number, precisionBits, exponentBits){
var bias = Math.pow(2, exponentBits - 1) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits,
status = isNaN(n = parseFloat(number)) || n == -Infinity || n == +Infinity ? n : 0,
exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array(len),
signal = (n = status !== 0 ? 0 : n) < 0, n = Math.abs(n), intPart = Math.floor(n), floatPart = n - intPart,
i, lastBit, rounded, j, result;
for(i = len; i; bin[--i] = 0);
for(i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
for(i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart);
for(i = -1; ++i < len && !bin[i];);
if(bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]){
if(!(rounded = bin[lastBit]))
for(j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
for(j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
}
for(i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);

(exp = bias + 1 - i) >= minExp && exp <= maxExp ? ++i : exp < minExp &&
(exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow"), i = bias + 1 - (exp = minExp - 1));
(intPart || status !== 0) && (this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status),
exp = maxExp + 1, i = bias + 2, status == -Infinity ? signal = 1 : isNaN(status) && (bin[i] = 1));
for(n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1);
for(n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = [];
i; n += (1 << j) * result.charAt(--i), j == 7 && (r[r.length] = String.fromCharCode(n), n = 0), j = (j + 1) % 8);
r[r.length] = n ? String.fromCharCode(n) : "";
return (this.bigEndian ? r.reverse() : r).join("");
};
p.encodeInt = function(number, bits, signed){
var max = Math.pow(2, bits), r = [];
(number >= max || number < -(max >> 1)) && this.warn("encodeInt::overflow") && (number = 0);
number < 0 && (number += max);
for(; number; r[r.length] = String.fromCharCode(number % 256), number = Math.floor(number / 256));
for(bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
return (this.bigEndian ? r.reverse() : r).join("");
};
p.decodeFloat = function(data, precisionBits, exponentBits){
var b = ((b = new this.Buffer(this.bigEndian, data)).checkBuffer(precisionBits + exponentBits + 1), b),
bias = Math.pow(2, exponentBits - 1) - 1, signal = b.readBits(precisionBits + exponentBits, 1),
exponent = b.readBits(precisionBits, exponentBits), significand = 0,
divisor = 2, curByte = b.buffer.length + (-precisionBits >> 3) - 1,
byteValue, startBit, mask;
do
for(byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit;
mask >>= 1; (byteValue & mask) && (significand += 1 / divisor), divisor *= 2);
while(precisionBits -= startBit);
return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity
: (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand
: Math.pow(2, exponent - bias) * (1 + significand) : 0);
};
p.decodeInt = function(data, bits, signed){
var b = new this.Buffer(this.bigEndian, data), x = b.readBits(0, bits), max = Math.pow(2, bits);
return signed && x >= max / 2 ? x - max : x;
};
with({p: (p.Buffer = function(bigEndian, buffer){
this.bigEndian = bigEndian || 0, this.buffer = [], this.setBuffer(buffer);
}).prototype}){
p.readBits = function(start, length){
//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
function shl(a, b){
for(++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
return a;
}
if(start < 0 || length <= 0)
return 0;
this.checkBuffer(start + length);
for(var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - (start >> 3) - 1,
lastByte = this.buffer.length + (-(start + length) >> 3), diff = curByte - lastByte,
sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1))
+ (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[ lastByte++ ] & ((1 << offsetLeft) - 1))
<< (diff-- << 3) - offsetRight : 0); diff; sum += shl(this.buffer[ lastByte++ ], (diff-- << 3) - offsetRight)
);
return sum;
};
p.setBuffer = function(data){
if(data){
for(var l, i = l = data.length, b = this.buffer = new Array(l); i; b[l - i] = data.charCodeAt(--i));
this.bigEndian && b.reverse();
}
};
p.hasNeededBits = function(neededBits){
return this.buffer.length >= -(-neededBits >> 3);
};
p.checkBuffer = function(neededBits){
if(!this.hasNeededBits(neededBits))
throw new Error("checkBuffer::missing bytes");
};
}
p.warn = function(msg){
if(this.allowExceptions)
throw new Error(msg);
return 1;
};
p.toSmall = function(data){return this.decodeInt(data, 8, true);};
p.fromSmall = function(number){return this.encodeInt(number, 8, true);};
p.toByte = function(data){return this.decodeInt(data, 8, false);};
p.fromByte = function(number){return this.encodeInt(number, 8, false);};
p.toShort = function(data){return this.decodeInt(data, 16, true);};
p.fromShort = function(number){return this.encodeInt(number, 16, true);};
p.toWord = function(data){return this.decodeInt(data, 16, false);};
p.fromWord = function(number){return this.encodeInt(number, 16, false);};
p.toInt = function(data){return this.decodeInt(data, 32, true);};
p.fromInt = function(number){return this.encodeInt(number, 32, true);};
p.toDWord = function(data){return this.decodeInt(data, 32, false);};
p.fromDWord = function(number){return this.encodeInt(number, 32, false);};
p.toFloat = function(data){return this.decodeFloat(data, 23, 8);};
p.fromFloat = function(number){return this.encodeFloat(number, 23, 8);};
p.toDouble = function(data){return this.decodeFloat(data, 52, 11);};
p.fromDouble = function(number){return this.encodeFloat(number, 52, 11);};
}
12 changes: 4 additions & 8 deletions node-amf/deserialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var amf = require('./amf');
var utils = require('./utils');
var utf8 = require('./utf8');
var unpack = require('./unpack').unpack;
var bin = require('./bin');
var createHeader = require('./header').createHeader;
var createMessage = require('./message').createMessage;

Expand All @@ -27,6 +28,7 @@ function AMFDeserializer( src ){
this.s = src || '';
this.i = 0;
this.resetRefs();
this.binParser = bin.parser( false, true );
}


Expand Down Expand Up @@ -87,14 +89,8 @@ AMFDeserializer.prototype.readU32 = function(){
/** */
AMFDeserializer.prototype.readDouble = function(){
var s = this.shiftBytes(8);
// big endian requires byte reversal
s = utils.reverseString(s);
//sys.puts('readDouble ['+escape(s)+']');
var unpacked = unpack('dflt',s);
if( ! unpacked || unpacked.flt == null ){
throw new Error('Failed to read double, ending at offset '+this.i);
}
return unpacked.flt;
var n = this.binParser.toDouble( s );
return n;
}


Expand Down
13 changes: 11 additions & 2 deletions node-amf/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var amf = require('./amf');
var utils = require('./utils');
var utf8 = require('./utf8');
var pack = require('./pack').pack;
var bin = require('./bin');


exports.createSerializer = function( v ){
Expand All @@ -23,6 +24,7 @@ function AMFSerializer( v ){
this.version = v;
this.s = '';
this.resetRefs();
this.binParser = bin.parser( false, true );
}


Expand Down Expand Up @@ -260,8 +262,15 @@ AMFSerializer.prototype.writeDouble = function( value, writeMarker ){
var marker = this.version === amf.AMF3 ? amf.AMF3_DOUBLE : amf.AMF0_NUMBER;
this.writeU8( marker );
}
var s = pack('d',value);
return this.s += utils.reverseString(s);
// support for NaN as double "00 00 00 00 00 00 F8 7F"
if( isNaN(value) ){
this.s += '\0\0\0\0\0\0\xF8\x7F';
//this.s += '\x7F\xF8\0\0\0\0\0\0';
}
else {
this.s += this.binParser.fromDouble( value );
}
return this.s;
}


Expand Down

0 comments on commit 9900fb3

Please sign in to comment.