|
|
|
/**
|
|
|
|
* Simple synchronous parser based on node-binary.
|
|
|
|
*/
|
|
|
|
|
|
|
|
function spec(b) {
|
|
|
|
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);
|
|
|
|
};
|
|
|
|
|
|
|
|
return Parser;
|
|
|
|
};
|
|
|
|
module.defineClass(spec);
|