Interpretador De Dados Binário //Repositório JavaScript

Descrição

Serializa e unserializa dados binários.
Criado: 2005.08.08

Código (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);};
}

Exemplo (Exemplo)

<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>

Ajuda

Esta classe é capaz de serializar e unserializar dados binários, então você pode ler arquivos gerados em C, pascal, etc bem como gerar tais dados. Ela também é capaz de lidar com a ordenação dos bytes (big/little endian) e suporta os seguintes tipos: signed integer (small 8 bits, short 16 bits, int 32 bits), unsigned integer (byte 8 bits, word 16 bits, dword 32 bits) e floating point (IEEE754 float 32 bits e double 64 bits).

Construtor

BinaryParser([bigEndian: Boolean = false], [allowExceptions: Boolean = false])
Gera uma instância de BinaryParser.
bigEndian
se setado em true, a classe irá assumir o formato bigEndian tanto no input quanto no output, caso contrário, utilizará o little endian.
allowExceptions
se true, quando houver erro na conversão número => binário será gerada uma exception que poderá ser capturada através de "try..except"

Propriedades

BinaryParser.bigEndian: Boolean
se setado em true, a classe irá assumir o formato bigEndian tanto no input quanto no output, caso contrário, utilizará o little endian.
BinaryParser.allowExceptions: Boolean
se true, quando houver erro na conversão número=>binário será gerada uma exception que poderá ser capturada através de "try..except"

Métodos Genéricos

BinaryParser.decodeFloat(data: String, precisionBits: Integer, exponentBits: Integer): Float
Decodifica uma string contendo a representação binária de um número no padrão IEEE-754 e retorna o número que ela representa ou os seguintes valores especiais: NaN, +Infinity, -Infinity.
data
string contendo a representação binária do número (deve conter no mínimo "ceil((exponentBits + precisionBits + 1) / 8)" bytes)
precisionBits
quantidade de bits que especificam a precisão/mantissa
exponentBits
quantidade de bits que representam o exponente
BinaryParser.encodeFloat(number: Float, precisionBits: Integer, exponentBits: Integer): String
Codifica um número no padrão IEEE-754 e retorna a representação binária do número em uma string contendo "ceil((exponentBits + precisionBits + 1) / 8)" bytes.
number
número a ser convertido
precisionBits
quantidade de bits que especificam a precisão/mantissa
exponentBits
quantidade de bits que representam o exponente
BinaryParser.decodeInt(data: String, bits: Integer, signed: Boolean): Integer
Decodifica uma string contendo dados binários e retorna o número que ela representa.
data
string contendo a representação binária do número (deve conter no mínimo "ceil(bits / 8)" bytes)
bits
quantidade de bits que especifica o máximo de números que podem ser representados
signed
indica se o número deve ser decodificado com sinal ou sem sinal
BinaryParser.encodeInt(number: Integer, bits: Integer, signed: Boolean): Integer
Codifica um número inteiro e retorna sua representação binária em uma string contendo "ceil(bits / 8)" bytes.
number
número a ser convertido
bits
quantidade de bits que especifica o máximo de números que podem ser representados
signed
indica se o número deve ser codificado com sinal ou sem sinal

Métodos (Ponto Flutuante)

BinaryParser.toFloat(data: String): Float
Retorna um float ou um valor especial (NaN, +Infinity, -Infinity).
data
string contendo no mínimo 4 bytes
BinaryParser.fromFloat(number: Float): String
Retorna sua representação binária em uma string, o método pode gerar exceções caso a propriedade "allowExceptions" esteja setada em true e o número seja um valor especial (NaN, +Infinity, -Infinity) ou se o número não puder ser representado (overflow, underflow).
number
número a ser convertido para binário
BinaryParser.toDouble(data: String): Float
Retorna um float ou um valor especial (NaN, +Infinity, -Infinity).
data
string contendo no mínimo 8 bytes
BinaryParser.fromDouble(number: Float): String
Retorna sua representação binária em uma string, o método pode gerar exceções caso a propriedade "allowExceptions" esteja setada em true e o número seja um valor especial (NaN, +Infinity, -Infinity) ou se o número não puder ser representado (overflow, underflow).
number
número a ser convertido para binário

Métodos (Números Inteiros)

BinaryParser.toSmall(data: String): Integer
Recebe string e retorna sua representação inteira com sinal.
data
string contendo no mínimo 1 byte
BinaryParser.fromSmall(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 1 byte, o método pode gerar uma exceção caso o número seja grande demais para ser representado e a propriedade "allowExceptions" esteja setada em true.
number
número a ser convertido para binário
BinaryParser.toByte(data: String): Integer
Recebe string e retorna sua representação inteira sem sinal.
data
string contendo no mínimo 1 byte
BinaryParser.fromByte(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 1 byte, o método pode gerar uma exceção caso o número seja grande demais para ser representado.
number
número a ser convertido para binário, a classe ignora se o número é negativo ou não (em complemento de 2, "-1" é representado da mesma forma que "255")
BinaryParser.toShort(data: String): Integer
Recebe string e retorna sua representação inteira com sinal.
data
string contendo no mínimo 2 bytes
BinaryParser.fromShort(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 2 bytes, o método pode gerar uma exceção caso o número seja grande demais para ser representado e a propriedade "allowExceptions" esteja setada em true.
number
número a ser convertido para binário
BinaryParser.toWord(data: String): Integer
Recebe string e retorna sua representação inteira sem sinal.
data
string contendo no mínimo 2 bytes
BinaryParser.fromWord(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 2 bytes, o método pode gerar uma exceção caso o número seja grande demais para ser representado.
number
número a ser convertido para binário, a classe ignora se o número é negativo ou não (em complemento de 2, "-1" é representado da mesma forma que "255")
BinaryParser.toInt(data: String): Integer
Recebe string e retorna sua representação inteira com sinal.
data
string contendo no mínimo 4 bytes
BinaryParser.fromInt(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 4 bytes, o método pode gerar uma exceção caso o número seja grande demais para ser representado e a propriedade "allowExceptions" esteja setada em true.
number
número a ser convertido para binário
BinaryParser.toDWord(data: String): Integer
Recebe string e retorna sua representação inteira sem sinal.
data
string contendo no mínimo 4 bytes
BinaryParser.fromDWord(number: Integer): String
Recebe um inteiro e retorna sua representação binária em uma string com 4 bytes, o método pode gerar uma exceção caso o número seja grande demais para ser representado.
number
número a ser convertido para binário, a classe ignora se o número é negativo ou não (em complemento de 2, "-1" é representado da mesma forma que "255")

Ranque (Votos: 141)

2.77