123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- var Chainsaw = require('chainsaw');
- var EventEmitter = require('events').EventEmitter;
- var Buffers = require('buffers');
- var Vars = require('./lib/vars.js');
- var Stream = require('stream').Stream;
- exports = module.exports = function (bufOrEm, eventName) {
- if (Buffer.isBuffer(bufOrEm)) {
- return exports.parse(bufOrEm);
- }
-
- var s = exports.stream();
- if (bufOrEm && bufOrEm.pipe) {
- bufOrEm.pipe(s);
- }
- else if (bufOrEm) {
- bufOrEm.on(eventName || 'data', function (buf) {
- s.write(buf);
- });
-
- bufOrEm.on('end', function () {
- s.end();
- });
- }
- return s;
- };
- exports.stream = function (input) {
- if (input) return exports.apply(null, arguments);
-
- var pending = null;
- function getBytes (bytes, cb, skip) {
- pending = {
- bytes : bytes,
- skip : skip,
- cb : function (buf) {
- pending = null;
- cb(buf);
- },
- };
- dispatch();
- }
-
- var offset = null;
- function dispatch () {
- if (!pending) {
- if (caughtEnd) done = true;
- return;
- }
- if (typeof pending === 'function') {
- pending();
- }
- else {
- var bytes = offset + pending.bytes;
-
- if (buffers.length >= bytes) {
- var buf;
- if (offset == null) {
- buf = buffers.splice(0, bytes);
- if (!pending.skip) {
- buf = buf.slice();
- }
- }
- else {
- if (!pending.skip) {
- buf = buffers.slice(offset, bytes);
- }
- offset = bytes;
- }
-
- if (pending.skip) {
- pending.cb();
- }
- else {
- pending.cb(buf);
- }
- }
- }
- }
-
- function builder (saw) {
- function next () { if (!done) saw.next() }
-
- var self = words(function (bytes, cb) {
- return function (name) {
- getBytes(bytes, function (buf) {
- vars.set(name, cb(buf));
- next();
- });
- };
- });
-
- self.tap = function (cb) {
- saw.nest(cb, vars.store);
- };
-
- self.into = function (key, cb) {
- if (!vars.get(key)) vars.set(key, {});
- var parent = vars;
- vars = Vars(parent.get(key));
-
- saw.nest(function () {
- cb.apply(this, arguments);
- this.tap(function () {
- vars = parent;
- });
- }, vars.store);
- };
-
- self.flush = function () {
- vars.store = {};
- next();
- };
-
- self.loop = function (cb) {
- var end = false;
-
- saw.nest(false, function loop () {
- this.vars = vars.store;
- cb.call(this, function () {
- end = true;
- next();
- }, vars.store);
- this.tap(function () {
- if (end) saw.next()
- else loop.call(this)
- }.bind(this));
- }, vars.store);
- };
-
- self.buffer = function (name, bytes) {
- if (typeof bytes === 'string') {
- bytes = vars.get(bytes);
- }
-
- getBytes(bytes, function (buf) {
- vars.set(name, buf);
- next();
- });
- };
-
- self.skip = function (bytes) {
- if (typeof bytes === 'string') {
- bytes = vars.get(bytes);
- }
-
- getBytes(bytes, function () {
- next();
- });
- };
-
- self.scan = function find (name, search) {
- if (typeof search === 'string') {
- search = new Buffer(search);
- }
- else if (!Buffer.isBuffer(search)) {
- throw new Error('search must be a Buffer or a string');
- }
-
- var taken = 0;
- pending = function () {
- var pos = buffers.indexOf(search, offset + taken);
- var i = pos-offset-taken;
- if (pos !== -1) {
- pending = null;
- if (offset != null) {
- vars.set(
- name,
- buffers.slice(offset, offset + taken + i)
- );
- offset += taken + i + search.length;
- }
- else {
- vars.set(
- name,
- buffers.slice(0, taken + i)
- );
- buffers.splice(0, taken + i + search.length);
- }
- next();
- dispatch();
- } else {
- i = Math.max(buffers.length - search.length - offset - taken, 0);
- }
- taken += i;
- };
- dispatch();
- };
-
- self.peek = function (cb) {
- offset = 0;
- saw.nest(function () {
- cb.call(this, vars.store);
- this.tap(function () {
- offset = null;
- });
- });
- };
-
- return self;
- };
-
- var stream = Chainsaw.light(builder);
- stream.writable = true;
-
- var buffers = Buffers();
-
- stream.write = function (buf) {
- buffers.push(buf);
- dispatch();
- };
-
- var vars = Vars();
-
- var done = false, caughtEnd = false;
- stream.end = function () {
- caughtEnd = true;
- };
-
- stream.pipe = Stream.prototype.pipe;
- Object.getOwnPropertyNames(EventEmitter.prototype).forEach(function (name) {
- stream[name] = EventEmitter.prototype[name];
- });
-
- return stream;
- };
- exports.parse = function parse (buffer) {
- var self = words(function (bytes, cb) {
- return function (name) {
- if (offset + bytes <= buffer.length) {
- var buf = buffer.slice(offset, offset + bytes);
- offset += bytes;
- vars.set(name, cb(buf));
- }
- else {
- vars.set(name, null);
- }
- return self;
- };
- });
-
- var offset = 0;
- var vars = Vars();
- self.vars = vars.store;
-
- self.tap = function (cb) {
- cb.call(self, vars.store);
- return self;
- };
-
- self.into = function (key, cb) {
- if (!vars.get(key)) {
- vars.set(key, {});
- }
- var parent = vars;
- vars = Vars(parent.get(key));
- cb.call(self, vars.store);
- vars = parent;
- return self;
- };
-
- self.loop = function (cb) {
- var end = false;
- var ender = function () { end = true };
- while (end === false) {
- cb.call(self, ender, vars.store);
- }
- return self;
- };
-
- self.buffer = function (name, size) {
- if (typeof size === 'string') {
- size = vars.get(size);
- }
- var buf = buffer.slice(offset, Math.min(buffer.length, offset + size));
- offset += size;
- vars.set(name, buf);
-
- return self;
- };
-
- self.skip = function (bytes) {
- if (typeof bytes === 'string') {
- bytes = vars.get(bytes);
- }
- offset += bytes;
-
- return self;
- };
-
- self.scan = function (name, search) {
- if (typeof search === 'string') {
- search = new Buffer(search);
- }
- else if (!Buffer.isBuffer(search)) {
- throw new Error('search must be a Buffer or a string');
- }
- vars.set(name, null);
-
- // simple but slow string search
- for (var i = 0; i + offset <= buffer.length - search.length + 1; i++) {
- for (
- var j = 0;
- j < search.length && buffer[offset+i+j] === search[j];
- j++
- );
- if (j === search.length) break;
- }
-
- vars.set(name, buffer.slice(offset, offset + i));
- offset += i + search.length;
- return self;
- };
-
- self.peek = function (cb) {
- var was = offset;
- cb.call(self, vars.store);
- offset = was;
- return self;
- };
-
- self.flush = function () {
- vars.store = {};
- return self;
- };
-
- self.eof = function () {
- return offset >= buffer.length;
- };
-
- return self;
- };
- // 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 words (decode) {
- var self = {};
-
- [ 1, 2, 4, 8 ].forEach(function (bytes) {
- var bits = bytes * 8;
-
- self['word' + bits + 'le']
- = self['word' + bits + 'lu']
- = decode(bytes, decodeLEu);
-
- self['word' + bits + 'ls']
- = decode(bytes, decodeLEs);
-
- self['word' + bits + 'be']
- = self['word' + bits + 'bu']
- = decode(bytes, decodeBEu);
-
- self['word' + bits + 'bs']
- = decode(bytes, decodeBEs);
- });
-
- // word8be(n) == word8le(n) for all n
- self.word8 = self.word8u = self.word8be;
- self.word8s = self.word8bs;
-
- return self;
- }
|