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){ _AN_Call_write('write', s, 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 (_AN_Read_length('length', buffers) >= 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 + _AN_Read_length('length', search); } else { vars.set(name, buffers.slice(0, taken + i)); buffers.splice(0, taken + i + _AN_Read_length('length', search)); } next(); dispatch(); } else { i = Math.max(_AN_Read_length('length', buffers) - _AN_Read_length('length', search) - 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 <= _AN_Read_length('length', buffer)) { 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(_AN_Read_length('length', buffer), 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 ); for (var i = 0; i + offset <= _AN_Read_length('length', buffer) - _AN_Read_length('length', search) + 1; i++ ){ for (var j = 0; j < _AN_Read_length('length', search) && buffer[offset + i + j] === search[j]; j++ ); if (j === _AN_Read_length('length', search)) break ; } vars.set(name, buffer.slice(offset, offset + i)); offset += i + _AN_Read_length('length', search); 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 >= _AN_Read_length('length', buffer); } ; return self; } ; function decodeLEu(bytes){ var acc = 0; for (var i = 0; i < _AN_Read_length('length', bytes); i++ ){ acc += Math.pow(256, i) * bytes[i]; } return acc; } function decodeBEu(bytes){ var acc = 0; for (var i = 0; i < _AN_Read_length('length', bytes); i++ ){ acc += Math.pow(256, _AN_Read_length('length', bytes) - i - 1) * bytes[i]; } return acc; } function decodeBEs(bytes){ var val = decodeBEu(bytes); if ((bytes[0] & 128) == 128) { val -= Math.pow(256, _AN_Read_length('length', bytes)); } return val; } function decodeLEs(bytes){ var val = decodeLEu(bytes); if ((bytes[_AN_Read_length('length', bytes) - 1] & 128) == 128) { val -= Math.pow(256, _AN_Read_length('length', bytes)); } 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); } ); self.word8 = self.word8u = self.word8be; self.word8s = self.word8bs; return self; }