comment author = ip comment author info = origin of ip ip addr is jank ( uses php public server for ip get) fuck apache reverse proxy ip change thigy thing comment command started config stuff started planning logging system
398 lines
10 KiB
JavaScript
398 lines
10 KiB
JavaScript
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;
|
|
}
|