mirror of
https://github.com/mgerb/mywebsite
synced 2026-01-12 02:42:48 +00:00
386 lines
12 KiB
JavaScript
386 lines
12 KiB
JavaScript
/**
|
|
* Binary Parser.
|
|
* Jonas Raoni Soares Silva
|
|
* http://jsfromhell.com/classes/binary-parser [v1.0]
|
|
*/
|
|
var chr = String.fromCharCode;
|
|
|
|
var maxBits = [];
|
|
for (var i = 0; i < 64; i++) {
|
|
maxBits[i] = Math.pow(2, i);
|
|
}
|
|
|
|
function BinaryParser (bigEndian, allowExceptions) {
|
|
if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions);
|
|
|
|
this.bigEndian = bigEndian;
|
|
this.allowExceptions = allowExceptions;
|
|
};
|
|
|
|
BinaryParser.warn = function warn (msg) {
|
|
if (this.allowExceptions) {
|
|
throw new Error(msg);
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) {
|
|
var b = new this.Buffer(this.bigEndian, data);
|
|
|
|
b.checkBuffer(precisionBits + exponentBits + 1);
|
|
|
|
var bias = maxBits[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;
|
|
|
|
do {
|
|
for (var 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 );
|
|
};
|
|
|
|
BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) {
|
|
var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
|
|
, x = b.readBits(0, bits)
|
|
, max = maxBits[bits]; //max = Math.pow( 2, bits );
|
|
|
|
return signed && x >= max / 2
|
|
? x - max
|
|
: x;
|
|
};
|
|
|
|
BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) {
|
|
var bias = maxBits[exponentBits - 1] - 1
|
|
, minExp = -bias + 1
|
|
, maxExp = bias
|
|
, minUnnormExp = minExp - precisionBits
|
|
, n = parseFloat(data)
|
|
, status = isNaN(n) || 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
|
|
, intPart = Math.floor(n = Math.abs(n))
|
|
, floatPart = n - intPart
|
|
, lastBit
|
|
, rounded
|
|
, result
|
|
, i
|
|
, j;
|
|
|
|
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];);
|
|
|
|
if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) {
|
|
++i;
|
|
} else if (exp < minExp) {
|
|
exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow");
|
|
i = bias + 1 - (exp = minExp - 1);
|
|
}
|
|
|
|
if (intPart || status !== 0) {
|
|
this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status);
|
|
exp = maxExp + 1;
|
|
i = bias + 2;
|
|
|
|
if (status == -Infinity) {
|
|
signal = 1;
|
|
} else if (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; j = (j + 1) % 8) {
|
|
n += (1 << j) * result.charAt(--i);
|
|
if (j == 7) {
|
|
r[r.length] = String.fromCharCode(n);
|
|
n = 0;
|
|
}
|
|
}
|
|
|
|
r[r.length] = n
|
|
? String.fromCharCode(n)
|
|
: "";
|
|
|
|
return (this.bigEndian ? r.reverse() : r).join("");
|
|
};
|
|
|
|
BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
|
|
var max = maxBits[bits];
|
|
|
|
if (data >= max || data < -(max / 2)) {
|
|
this.warn("encodeInt::overflow");
|
|
data = 0;
|
|
}
|
|
|
|
if (data < 0) {
|
|
data += max;
|
|
}
|
|
|
|
for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));
|
|
|
|
for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
|
|
|
|
return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
|
|
};
|
|
|
|
BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
|
|
BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
|
|
BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
|
|
BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
|
|
BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
|
|
BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
|
|
BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
|
|
BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
|
|
BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
|
|
BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
|
|
BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
|
|
BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
|
|
BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
|
|
BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
|
|
BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
|
|
BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
|
|
BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
|
|
BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
|
|
BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
|
|
BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
|
|
|
|
// Factor out the encode so it can be shared by add_header and push_int32
|
|
BinaryParser.encode_int32 = function encode_int32 (number, asArray) {
|
|
var a, b, c, d, unsigned;
|
|
unsigned = (number < 0) ? (number + 0x100000000) : number;
|
|
a = Math.floor(unsigned / 0xffffff);
|
|
unsigned &= 0xffffff;
|
|
b = Math.floor(unsigned / 0xffff);
|
|
unsigned &= 0xffff;
|
|
c = Math.floor(unsigned / 0xff);
|
|
unsigned &= 0xff;
|
|
d = Math.floor(unsigned);
|
|
return asArray ? [chr(a), chr(b), chr(c), chr(d)] : chr(a) + chr(b) + chr(c) + chr(d);
|
|
};
|
|
|
|
BinaryParser.encode_int64 = function encode_int64 (number) {
|
|
var a, b, c, d, e, f, g, h, unsigned;
|
|
unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
|
|
a = Math.floor(unsigned / 0xffffffffffffff);
|
|
unsigned &= 0xffffffffffffff;
|
|
b = Math.floor(unsigned / 0xffffffffffff);
|
|
unsigned &= 0xffffffffffff;
|
|
c = Math.floor(unsigned / 0xffffffffff);
|
|
unsigned &= 0xffffffffff;
|
|
d = Math.floor(unsigned / 0xffffffff);
|
|
unsigned &= 0xffffffff;
|
|
e = Math.floor(unsigned / 0xffffff);
|
|
unsigned &= 0xffffff;
|
|
f = Math.floor(unsigned / 0xffff);
|
|
unsigned &= 0xffff;
|
|
g = Math.floor(unsigned / 0xff);
|
|
unsigned &= 0xff;
|
|
h = Math.floor(unsigned);
|
|
return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
|
|
};
|
|
|
|
/**
|
|
* UTF8 methods
|
|
*/
|
|
|
|
// Take a raw binary string and return a utf8 string
|
|
BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) {
|
|
var len = binaryStr.length
|
|
, decoded = ''
|
|
, i = 0
|
|
, c = 0
|
|
, c1 = 0
|
|
, c2 = 0
|
|
, c3;
|
|
|
|
while (i < len) {
|
|
c = binaryStr.charCodeAt(i);
|
|
if (c < 128) {
|
|
decoded += String.fromCharCode(c);
|
|
i++;
|
|
} else if ((c > 191) && (c < 224)) {
|
|
c2 = binaryStr.charCodeAt(i+1);
|
|
decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
|
i += 2;
|
|
} else {
|
|
c2 = binaryStr.charCodeAt(i+1);
|
|
c3 = binaryStr.charCodeAt(i+2);
|
|
decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
|
i += 3;
|
|
}
|
|
}
|
|
|
|
return decoded;
|
|
};
|
|
|
|
// Encode a cstring
|
|
BinaryParser.encode_cstring = function encode_cstring (s) {
|
|
return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0);
|
|
};
|
|
|
|
// Take a utf8 string and return a binary string
|
|
BinaryParser.encode_utf8 = function encode_utf8 (s) {
|
|
var a = ""
|
|
, c;
|
|
|
|
for (var n = 0, len = s.length; n < len; n++) {
|
|
c = s.charCodeAt(n);
|
|
|
|
if (c < 128) {
|
|
a += String.fromCharCode(c);
|
|
} else if ((c > 127) && (c < 2048)) {
|
|
a += String.fromCharCode((c>>6) | 192) ;
|
|
a += String.fromCharCode((c&63) | 128);
|
|
} else {
|
|
a += String.fromCharCode((c>>12) | 224);
|
|
a += String.fromCharCode(((c>>6) & 63) | 128);
|
|
a += String.fromCharCode((c&63) | 128);
|
|
}
|
|
}
|
|
|
|
return a;
|
|
};
|
|
|
|
BinaryParser.hprint = function hprint (s) {
|
|
var number;
|
|
|
|
for (var i = 0, len = s.length; i < len; i++) {
|
|
if (s.charCodeAt(i) < 32) {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(16)
|
|
: s.charCodeAt(i).toString(16);
|
|
process.stdout.write(number + " ")
|
|
} else {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(16)
|
|
: s.charCodeAt(i).toString(16);
|
|
process.stdout.write(number + " ")
|
|
}
|
|
}
|
|
|
|
process.stdout.write("\n\n");
|
|
};
|
|
|
|
BinaryParser.ilprint = function hprint (s) {
|
|
var number;
|
|
|
|
for (var i = 0, len = s.length; i < len; i++) {
|
|
if (s.charCodeAt(i) < 32) {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(10)
|
|
: s.charCodeAt(i).toString(10);
|
|
|
|
require('util').debug(number+' : ');
|
|
} else {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(10)
|
|
: s.charCodeAt(i).toString(10);
|
|
require('util').debug(number+' : '+ s.charAt(i));
|
|
}
|
|
}
|
|
};
|
|
|
|
BinaryParser.hlprint = function hprint (s) {
|
|
var number;
|
|
|
|
for (var i = 0, len = s.length; i < len; i++) {
|
|
if (s.charCodeAt(i) < 32) {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(16)
|
|
: s.charCodeAt(i).toString(16);
|
|
require('util').debug(number+' : ');
|
|
} else {
|
|
number = s.charCodeAt(i) <= 15
|
|
? "0" + s.charCodeAt(i).toString(16)
|
|
: s.charCodeAt(i).toString(16);
|
|
require('util').debug(number+' : '+ s.charAt(i));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* BinaryParser buffer constructor.
|
|
*/
|
|
function BinaryParserBuffer (bigEndian, buffer) {
|
|
this.bigEndian = bigEndian || 0;
|
|
this.buffer = [];
|
|
this.setBuffer(buffer);
|
|
};
|
|
|
|
BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) {
|
|
var l, i, b;
|
|
|
|
if (data) {
|
|
i = l = data.length;
|
|
b = this.buffer = new Array(l);
|
|
for (; i; b[l - i] = data.charCodeAt(--i));
|
|
this.bigEndian && b.reverse();
|
|
}
|
|
};
|
|
|
|
BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) {
|
|
return this.buffer.length >= -(-neededBits >> 3);
|
|
};
|
|
|
|
BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) {
|
|
if (!this.hasNeededBits(neededBits)) {
|
|
throw new Error("checkBuffer::missing bytes");
|
|
}
|
|
};
|
|
|
|
BinaryParserBuffer.prototype.readBits = function readBits (start, length) {
|
|
//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
|
|
|
|
function shl (a, b) {
|
|
for (; 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);
|
|
|
|
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);
|
|
|
|
for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight));
|
|
|
|
return sum;
|
|
};
|
|
|
|
/**
|
|
* Expose.
|
|
*/
|
|
BinaryParser.Buffer = BinaryParserBuffer;
|
|
|
|
exports.BinaryParser = BinaryParser;
|