bitcore/util/BinaryParser.js

138 lines
3.2 KiB
JavaScript

/**
* Simple synchronous parser based on node-binary.
*/
function Parser(buffer) {
this.subject = buffer;
this.pos = 0;
};
Parser.prototype.buffer = function buffer(len) {
var buf = this.subject.slice(this.pos, this.pos + len);
this.pos += len;
return buf;
};
Parser.prototype.search = function search(needle) {
var len;
if ("string" === typeof needle || Buffer.isBuffer(needle)) {
// TODO: Slicing is probably too slow
len = this.subject.slice(this.pos).indexOf(needle);
if (len !== -1) {
this.pos += len + needle.length;
}
return len;
}
if ("number" === typeof needle) {
needle = needle & 0xff;
// Search for single byte
for (var i = this.pos, l = this.subject.length; i < l; i++) {
if (this.subject[i] == needle) {
len = i - this.pos;
this.pos = i + 1;
return len;
}
}
return -1;
}
};
/**
* Like search(), but returns the skipped bytes
*/
Parser.prototype.scan = function scan(needle) {
var startPos = this.pos;
var len = this.search(needle);
if (len !== -1) {
return this.subject.slice(startPos, startPos + len);
} else {
throw new Error('No match');
}
};
Parser.prototype.eof = function eof() {
return this.pos >= this.subject.length;
};
// convert byte strings to unsigned little endian numbers
function decodeLEu(bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, i) * bytes[i];
}
return acc;
}
// convert byte strings to unsigned big endian numbers
function decodeBEu(bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
}
return acc;
}
// convert byte strings to signed big endian numbers
function decodeBEs(bytes) {
var val = decodeBEu(bytes);
if ((bytes[0] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
// convert byte strings to signed little endian numbers
function decodeLEs(bytes) {
var val = decodeLEu(bytes);
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
function getDecoder(len, fn) {
return function() {
var buf = this.buffer(len);
return fn(buf);
};
};
[1, 2, 4, 8].forEach(function(bytes) {
var bits = bytes * 8;
Parser.prototype['word' + bits + 'le'] = Parser.prototype['word' + bits + 'lu'] = getDecoder(bytes, decodeLEu);
Parser.prototype['word' + bits + 'ls'] = getDecoder(bytes, decodeLEs);
Parser.prototype['word' + bits + 'be'] = Parser.prototype['word' + bits + 'bu'] = getDecoder(bytes, decodeBEu);
Parser.prototype['word' + bits + 'bs'] = getDecoder(bytes, decodeBEs);
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
Parser.prototype.word8s = Parser.prototype.word8bs;
});
Parser.prototype.varInt = function() {
var firstByte = this.word8();
switch (firstByte) {
case 0xFD:
return this.word16le();
case 0xFE:
return this.word32le();
case 0xFF:
return this.word64le();
default:
return firstByte;
}
};
Parser.prototype.varStr = function() {
var len = this.varInt();
return this.buffer(len);
};
module.exports = Parser;