Binary Parser //JavaScript Repository
Description
Serializes and unserializes binary data.
Created: 2005.08.08
Created: 2005.08.08
Code (Download)
//+ 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);};
}
Example (Example)
<form action="">
<fieldset>
<br /><input type="radio" name="endian" value="0" checked="checked" />Big Endian
<input type="radio" name="endian" value="1" />Little Endian
<br /><br />
<fieldset>
<legend>N?mero > Hexadecimal</legend>
Converter n?mero <input type="text" name="fromNumber" value="123" /> para
<select name="toHex">
<option value="Small">Small</option>
<option value="Byte">Byte</option>
<option value="Short">Short</option>
<option value="Word">Word</option>
<option value="Int">Int</option>
<option value="DWord">DWord</option>
<option value="Float">Float</option>
<option value="Double">Double</option>
</select>
<br /><input type="button" name="n2h" value="Converter" />
</fieldset>
<br />
<fieldset>
<legend>Hexadecimal > N?mero</legend>
Converter hexadecimal <input type="text" name="fromHex" value="7b" /> para n?mero
<select name="toNumber">
<option value="Small">Small</option>
<option value="Byte">Byte</option>
<option value="Short">Short</option>
<option value="Word">Word</option>
<option value="Int">Int</option>
<option value="DWord">DWord</option>
<option value="Float">Float</option>
<option value="Double">Double</option>
</select>
<br /><input type="button" name="h2n" value="Converter" />
</fieldset>
</fieldset>
</form>
<script type="text/javascript">
//<![CDATA[
f = document.forms[0];
//http://www.jsfromhell.com/geral/event-listener
addEvent(f.n2h, "click", function(e){
function char2hex(s){
for(var k, i = s.length, r = ""; i; r = ((k = s.charCodeAt(--i).toString(16 )).length - 1 ? k : "0" + k) + r);
return r;
}
try{
alert(char2hex((new BinaryParser(f.endian[0].checked, true))["from" + f.toHex.value](f.fromNumber.value - 0)));
}
catch(e){
alert('Erro\n'+e.message);
}
});
//http://www.jsfromhell.com/geral/event-listener
addEvent(f.h2n, "click", function(e){
function hex2bin(s){
for(var i = 0, l = s.length, r = ""; i < l; r += String.fromCharCode(parseInt(s.substr(i, 2), 16)), i += 2);
return r;
}
try{
alert((new BinaryParser(f.endian[0].checked, true))["to" + f.toNumber.value](hex2bin(f.fromHex.value)));
}
catch(e){
alert('Erro\n'+e.message);
}
} );
//]]>
</script>
Help
This class is able to serialize and unserialize binary data, so you can read files generated with C, pascal, etc as well as generate such data. It's also able to handle the byte order (big/little endian) and supports the following types: signed integer (small 8 bits, short 16 bits, int 32 bits), unsigned integer (byte 8 bits, word 16 bits, dword 32 bits) and floating point (IEEE754 float 32 bits and double 64 bits).
Constructor
- BinaryParser([bigEndian: Boolean = false], [allowExceptions: Boolean = false])
-
Generates an instance of BinaryParser.
- bigEndian
- if true, the class will assume the bigEndian format for the input and output, otherwise, it will assume the little endian format.
- allowExceptions
- if true, when number=>binary conversion error occur an exception will be raised (which can be caught through a "try..except" block)
Properties
- BinaryParser.bigEndian: Boolean
- if true, the class will assume the bigEndian format for the input and output, otherwise, it will assume the little endian format.
- BinaryParser.allowExceptions: Boolean
- if true, when number=>binary conversion error occur an exception will be raised (which can be caught through a "try..except" block)
Gerenic Methods
- BinaryParser.decodeFloat(data: String, precisionBits: Integer, exponentBits: Integer): Float
-
Decodes a string containing the binary representation of a number in the IEEE-754 pattern and returns the number or the following special values: NaN, +Infinity, -Infinity.
- data
- string containing the binary representation of the number (must contain at least "ceil((exponentBits + precisionBits + 1) / 8)" bytes)
- precisionBits
- amount of bits that specifies the precision/mantisse
- exponentBits
- amount of bits that specifies the exponent
- BinaryParser.encodeFloat(number: Float, precisionBits: Integer, exponentBits: Integer): String
-
Encodes a number into the IEEE-754 pattern and returns the binary representation of it in a string containing "ceil((exponentBits + precisionBits + 1) / 8)" bytes.
- number
- number to be converted
- precisionBits
- amount of bits that specifies the precision/mantisse
- exponentBits
- amount of bits that specifies the exponent
- BinaryParser.decodeInt(data: String, bits: Integer, signed: Boolean): Integer
-
Decodes a string containing binary data and returns the number that it represents.
- data
- string containing the binary representation of the number (must contain at least "ceil(bits / 8)" bytes)
- bits
- amount of bits that specifies the quantity of numbers that can be represented
- signed
- indicates if the number must be decoded with signal or without signal
- BinaryParser.encodeInt(number: Int, bits: Integer, signed: Boolean): Integer
-
Encodes an integer number and returns it's binary representation on a string containing "ceil(bits / 8)" bytes.
- number
- number to be converted
- bits
- amount of bits that specifies the quantity of numbers that can be represented
- signed
- indicates if the number must be encoded with signal or without signal
Methods (Float Point)
- BinaryParser.toFloat(data: String): Float
-
Returns a number or a special value (NaN, +Infinity, -Infinity).
- data
- string containing at least 4 bytes
- BinaryParser.fromFloat(number: Float): String
-
Returns the binary representation of a number in a string, the method can raise exceptions if the property "allowExceptions" is true and the number is an special value (NaN, +Infinity, -Infinity) or if it can't be represented (overflow, underflow).
- number
- number to be converted to binary
- BinaryParser.toDouble(data: String): Float
-
Returns a number or a special value (NaN, +Infinity, -Infinity).
- data
- string containing at least 8 bytes
- BinaryParser.fromDouble(number: Float): String
-
Returns the binary representation of a number in a string, the method can raise exceptions if the property "allowExceptions" is true and the number is an special value (NaN, +Infinity, -Infinity) or if it can't be represented (overflow, underflow).
- number
- number to be converted to binary
Methods (Integer Numbers)
- BinaryParser.toSmall(data: String): Integer
-
Receives a string and returns its integer value with signal.
- data
- string containing at least 1 bytes
- BinaryParser.fromSmall(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 1 byte, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary
- BinaryParser.toByte(data: String): Integer
-
Receives a string and returns its integer value without signal.
- data
- string containing at least 1 bytes
- BinaryParser.fromByte(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 1 byte, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary, the class ignores if the number is negative or not (in the two's complement, "-1" is represented in the same way as "255")
- BinaryParser.toShort(data: String): Integer
-
Receives a string and returns its integer value with signal.
- data
- string containing at least 2 bytes
- BinaryParser.fromShort(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 2 bytes, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary
- BinaryParser.toWord(data: String): Integer
-
Receives a string and returns its integer value without signal.
- data
- string containing at least 2 bytes
- BinaryParser.fromWord(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 2 bytes, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary, the class ignores if the number is negative or not (in the two's complement, "-1" is represented in the same way as "255")
- BinaryParser.toInt(data: String): Integer
-
Receives a string and returns its integer value with signal.
- data
- string containing at least 4 bytes
- BinaryParser.fromInt(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 4 bytes, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary
- BinaryParser.toDWord(data: String): Integer
-
Receives a string and returns its integer value without signal.
- data
- string containing at least 4 bytes
- BinaryParser.fromDWord(number: Integer): String
-
Receives an integer and returns its binary representation in a string with 4 bytes, the method can raise an exception if the number is too big to be represented and the property "allowExceptions" is true.
- number
- number to be converted to binary, the class ignores if the number is negative or not (in the two's complement, "-1" is represented in the same way as "255")
Rank (Votes: 141)
2.77