package/binary.js0000644000175000017500000003124411552674027014530 0ustar substacksubstackvar BufferList = require('bufferlist'); var EventEmitter = require('events').EventEmitter; var util = require('util'); module.exports = Binary; module.exports.Binary = Binary; // backwards compatibility Binary.prototype = new EventEmitter; function Binary(buffer) { if (!(this instanceof Binary)) return new Binary(buffer); var self = this; this.vars = {}; this.offset = 0; this.actions = []; this.parent = null; // an explicit end loads all the actions before any evaluation happens this.end = function () { if (buffer.listeners('write').indexOf(update) < 0) { buffer.on('write', update); } update(); return this; }; // Signify to the parent that processing should stop. this.exit = function () { this.pushAction({ ready : true, action : function () { this.actions = []; if (this.parent) this.parent.actions = []; }, }); return this; }; function update () { var action = self.actions[0]; if (!action) { buffer.removeListener('write', update); self.emit('end', self.vars); } else if (action.ready.call(self, self.vars)) { self.actions.shift(); if (action.context == false) { action.action.call(self, self.vars); self.end(); } else { buffer.removeListener('write', update); var child = new Binary(buffer); child.vars = self.vars; child.parent = self; child.offset = self.offset; child.on('end', function () { self.offset = child.offset; buffer.on('write', update); self.end(); }); action.action.call(child, child.vars); child.end(); } } } this.pushAction = function (action) { if (!action) throw "Action not specified"; var ready = { 'function' : action.ready, 'boolean' : function () { return action.ready }, }[typeof(action.ready)]; if (!ready) throw "Unknown action.ready type"; this.actions.push({ 'action' : action.action, 'ready' : ready, 'context' : action.context || false, }); }; this.flush = function () { this.pushAction({ ready : true, action : function () { buffer.advance(this.offset); this.offset = 0; }, }); return this; }; this.skip = function (bytes) { this.pushAction({ ready : true, action : function () { this.offset += bytes; }, }); return this; }; this.tap = function (f) { this.pushAction({ ready : true, context : true, action : function () { f.call(this, this.vars); }, }); return this; }; this.when = function (v1, v2, f) { var f1 = typeof(v1) == 'string' ? function (vars) { return lookup(this,v1) } : function (vars) { return v1 } ; var f2 = typeof(v2) == 'string' ? function (vars) { return lookup(this,v2) } : function (vars) { return v2 } ; return this.tap(function () { if (f1.call(this,this.vars) == f2.call(this,this.vars)) { f.call(this, this.vars); } }); }; this.unless = function (v1, v2, f) { var f1 = typeof(v1) == 'string' ? function (vars) { return lookup(this,v1) } : function (vars) { return v1 } ; var f2 = typeof(v2) == 'string' ? function (vars) { return lookup(this,v2) } : function (vars) { return v2 } ; return this.tap(function () { if (f1.call(this,this.vars) != f2.call(this,this.vars)) { f.call(this, this.vars); } }); }; this.repeat = function (n, f) { var nf = typeof(n) == 'string' ? function (vars) { return lookup(this,n) } : function (vars) { return n } ; this.pushAction({ ready : true, context : true, action : function () { var nn = nf.call(this, this.vars); for (var i = 0; i < nn; i++) { f.call(this, this.vars, i); } }, }); return this; }; this.forever = function (f) { self.foreverfunc = f; self.foreveraction = { ready : true, context : true, action : function () { self.foreverfunc.call(this, this.vars); self.pushAction(self.foreveraction); }, }; this.pushAction(self.foreveraction); return this; }; // assign immediately function assign (self, key, value) { visit( self, key instanceof Array ? key : [key], function (v,k) { v[k] = value } ); } function lookup (self) { var args = [].slice.call(arguments, 1); return visit(self, args, function (v,k) { return v[k] }); } function visit(self, args, f) { var keys = args.reduce(function (acc,x) { return acc.concat(x.split('.')) },[]) ; var obj = self.vars; keys.slice(0,-1).forEach(function (k) { if (!obj[k]) obj[k] = {}; obj = obj[k]; }); return f(obj, keys.slice(-1)[0]); } // Assign into a variable. All but the last argument make up the key, which // may describe a deeply nested address. If the last argument is a: // * function - assign the variables from the inner chain // * string - assign from the key name // * number - assign from this value this.into = function () { var args = [].concat.apply([],arguments); var keys = args.slice(0,-1); var fv = args.slice(-1)[0]; return this.tap(function (vars) { if (typeof fv == 'function') { var topVars = this.vars; this.vars = {}; fv.call(this, this.vars); this.pushAction({ ready : true, action : function () { var localVars = this.vars; this.vars = topVars; assign(this, keys, localVars); } }); } else if (typeof fv == 'string') { assign(this, keys, lookup(this,fv)); } else if (typeof fv == 'number') { assign(this, keys, fv); } else { throw TypeError( 'Last argument to .into must be a string, number, ' + 'or a function, not a "' + typeof fv + '".' + 'Value supplied: ' + util.inspect(fv) ); } }); }; function get (opts) { var into = [].reduce.call(opts.into, function (acc,x) { return acc.concat(x); }, []); this.pushAction({ ready : function () { return buffer.length - this.offset >= opts.bytes; }, action : function () { var data = buffer.join(this.offset, this.offset + opts.bytes); this.offset += opts.bytes; var decodeLittleEndian = opts.signed ? decodeLEs : decodeLE; var decodeBigEndian = opts.signed ? decodeBEs : decodeBE; assign(this, into, opts.endian && opts.endian == 'little' ? decodeLittleEndian(data) : decodeBigEndian(data) ); }, }); return this; }; this.getWord8 = function () { return get.call( this, { into : arguments, bytes : 1 } ); }; this.getWord16be = function () { return get.call( this, { into : arguments, bytes : 2, endian : 'big' } ); }; this.getWord16bes = function () { return get.call( this, { into : arguments, bytes : 2, endian : 'big', signed : true } ); } this.getWord16le = function () { return get.call( this, { into : arguments, bytes : 2, endian : 'little' } ); }; this.getWord16les = function () { return get.call( this, { into : arguments, bytes : 2, endian : 'little', signed : true } ); } this.getWord32be = function () { return get.call( this, { into : arguments, bytes : 4, endian : 'big' } ); }; this.getWord32bes = function () { return get.call( this, { into : arguments, bytes : 4, endian : 'big', signed : true } ); }; this.getWord32le = function () { return get.call( this, { into : arguments, bytes : 4, endian : 'little' } ); }; this.getWord32les = function () { return get.call( this, { into : arguments, bytes : 4, endian : 'little', signed: true } ); }; this.getWord64be = function () { return get.call( this, { into : arguments, bytes : 8, endian : 'big' } ); }; this.getWord64bes = function () { return get.call( this, { into : arguments, bytes : 8, endian : 'big', signed : true } ); }; this.getWord64le = function () { return get.call( this, { into : arguments, bytes : 8, endian : 'little' } ); }; this.getWord64les = function () { return get.call( this, { into : arguments, bytes : 8, endian : 'little', signed : true } ); }; this.getBuffer = function () { var args = [].concat.apply([],arguments); // flatten :into so .getBuffer(['foo','bar','baz'],10) // and .getBuffer('foo','bar','baz',10) both work var into = args.slice(0,-1).reduce(function f (acc,x) { return acc.concat( x instanceof Array ? x.reduce(f) : x.split('.') ); }, []); var length = args.slice(-1)[0]; var lengthF; if (typeof(length) == 'string') { var s = length; lengthF = function (vars) { return lookup(this,s) }; } else if (typeof(length) == 'number') { var s = length; lengthF = function (vars) { return s }; } else if (length instanceof Function) { lengthF = length; } else { throw TypeError( 'Last argument to getBuffer (length) must be a string, number, ' + 'or a function, not a "' + typeof(length) + '".' + 'Value supplied: ' + util.inspect(length) ); } this.pushAction({ ready : function () { var s = lengthF.call(this,this.vars); return s && buffer.length - this.offset >= s; }, action : function () { var s = lengthF.call(this,this.vars); var data = buffer.join(this.offset, this.offset + s); this.offset += s; assign(this, into, data); }, }); return this; }; } // convert byte strings to little endian numbers function decodeLE (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 big endian numbers function decodeBE (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 = decodeBE(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 = decodeLE(bytes); if ((bytes[bytes.length-1]&0x80) == 0x80) { val -= Math.pow(256, bytes.length); } return val; } package/package.json0000644000175000017500000000066611552674027015200 0ustar substacksubstack{ "name": "bufferlist", "version": "0.1.0", "description": "Create linked lists of Buffer objects", "directories": { "lib": "." }, "main": "./bufferlist", "repository": { "type": "git", "url": "http://github.com/substack/node-bufferlist.git" }, "devDependencies" : { "expresso": ">= 0.7.2" }, "scripts": { "test": "expresso" }, "engine": ["node >=0.1.97"] } package/README.markdown0000644000175000017500000000360211552674027015404 0ustar substacksubstackBufferList ========== BufferList provides an interface to treat a linked list of buffers as a single stream. This is useful for events that produce a many small Buffers, such as network streams. Installation ============ Install using npm: npm install bufferlist Or, check out the repository and have npm link to your development copy. This is useful for developing the library, and is necessary when running the tests, since they refer to the installed names of the library files. git clone http://github.com/substack/node-bufferlist.git cd node-bufferlist npm link . Simple Bufferlist Example ========================= #!/usr/bin/env node var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist').BufferList; var b = new BufferList; ['abcde','xyz','11358'].forEach(function (s) { var buf = new Buffer(s.length); buf.write(s); b.push(buf); }); sys.puts(b.take(10)); // abcdexyz11 Binary ====== This distribution also contains a Binary module for parsing these bufferlists. Simple Binary Example ===================== #!/usr/bin/env node var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist').BufferList; var Binary = require('bufferlist/binary').Binary; var bufferList = new BufferList; var binary = Binary(bufferList) .getWord16be('xLen') .getBuffer('xs', 'xLen') .tap(function (vars) { vars.moo = 'xs:' + vars.xLen + ':' + vars.xs; }) .end() ; var buf = new Buffer(6); buf.write('\x00\x04meow', 'binary'); bufferList.push(buf); sys.puts(binary.vars.moo); // xs:4:meow See Also ======== See the examples/ directory for more involved examples. See http://github.com/substack/node-rfb for a practical application of this distribution. package/LICENSE0000644000175000017500000000024511552674027013710 0ustar substacksubstackCopyright 2010 James Halliday (mail@substack.net) This project is free software released under the MIT license: http://www.opensource.org/licenses/mit-license.php package/bufferlist.js0000644000175000017500000001216111552674027015406 0ustar substacksubstack// bufferlist.js // Treat a linked list of buffers as a single variable-size buffer. var Buffer = require('buffer').Buffer; var EventEmitter = require('events').EventEmitter; module.exports = BufferList; module.exports.BufferList = BufferList; // backwards compatibility function BufferList(opts) { if (!(this instanceof BufferList)) return new BufferList(opts); EventEmitter.call(this); var self = this; if (typeof(opts) == 'undefined') opts = {}; // default encoding to use for take(). Leaving as 'undefined' // makes take() return a Buffer instead. self.encoding = opts.encoding; // constructor to use for Buffer-esque operations self.construct = opts.construct || Buffer; var head = { next : null, buffer : null }; var last = { next : null, buffer : null }; // length can get negative when advanced past the end // and this is the desired behavior var length = 0; self.__defineGetter__('length', function () { return length; }); // keep an offset of the head to decide when to head = head.next var offset = 0; // Write to the bufferlist. Emits 'write'. Always returns true. self.write = function (buf) { if (!head.buffer) { head.buffer = buf; last = head; } else { last.next = { next : null, buffer : buf }; last = last.next; } length += buf.length; self.emit('write', buf); return true; }; self.end = function (buf) { if (buf instanceof Buffer) self.write(buf); }; // Push buffers to the end of the linked list. (deprecated) // Return this (self). self.push = function () { var args = [].concat.apply([], arguments); args.forEach(self.write); return self; }; // For each buffer, perform some action. // If fn's result is a true value, cut out early. // Returns this (self). self.forEach = function (fn) { if (!head.buffer) return new self.construct(0); if (head.buffer.length - offset <= 0) return self; var firstBuf = new self.construct(head.buffer.length - offset); head.buffer.copy(firstBuf, 0, offset, head.buffer.length); var b = { buffer : firstBuf, next : head.next }; while (b && b.buffer) { var r = fn(b.buffer); if (r) break; b = b.next; } return self; }; // Create a single Buffer out of all the chunks or some subset specified by // start and one-past the end (like slice) in bytes. self.join = function (start, end) { if (!head.buffer) return new self.construct(0); if (start == undefined) start = 0; if (end == undefined) end = self.length; var big = new self.construct(end - start); var ix = 0; self.forEach(function (buffer) { if (start < (ix + buffer.length) && ix < end) { // at least partially contained in the range buffer.copy( big, Math.max(0, ix - start), Math.max(0, start - ix), Math.min(buffer.length, end - ix) ); } ix += buffer.length; if (ix > end) return true; // stop processing past end }); return big; }; // Advance the buffer stream by n bytes. // If n the aggregate advance offset passes the end of the buffer list, // operations such as .take() will return empty strings until enough data is // pushed. // Returns this (self). self.advance = function (n) { offset += n; length -= n; while (head.buffer && offset >= head.buffer.length) { offset -= head.buffer.length; head = head.next ? head.next : { buffer : null, next : null } ; } self.emit('advance', n); return self; }; // Take n bytes from the start of the buffers. // Returns a string. // If there are less than n bytes in all the buffers or n is undefined, // returns the entire concatenated buffer string. self.take = function (n, encoding) { if (n == undefined) n = self.length; else if (typeof n !== 'number') { encoding = n; n = self.length; } var b = head; if (!encoding) encoding = self.encoding; if (encoding) { var acc = ''; self.forEach(function (buffer) { if (n <= 0) return true; acc += buffer.toString( encoding, 0, Math.min(n,buffer.length) ); n -= buffer.length; }); return acc; } else { // If no 'encoding' is specified, then return a Buffer. return self.join(0, n); } }; // The entire concatenated buffer as a string. self.toString = function () { return self.take('binary'); }; } require('util').inherits(BufferList, EventEmitter); package/examples/binary.js0000644000175000017500000000276511552674027016354 0ustar substacksubstack#!/usr/bin/env node var sys = require('sys'); var net = require('net'); var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); function parser (sock) { var bufferList = new BufferList; sock.addListener('data', function (data) { bufferList.push(data); }); return Binary(bufferList) .getWord16be('xLen') .when('xLen', 0, function (vars) { this .getWord32le('msgLen') .getBuffer('msg', 'msgLen') .tap(function (vars) { vars.moo = 'msg:' + vars.msgLen + ':' + vars.msg; }) .exit() ; }) .getBuffer('xs', 'xLen') .tap(function (vars) { vars.moo = 'xs:' + vars.xLen + ':' + vars.xs; }) .end() ; } function serverSession (port, strings) { // fire up a server to write the strings when a client connects var server = net.createServer(function (stream) { strings.forEach(function (s) { stream.write(s); }); stream.end(); server.close(); }); server.listen(port); // connect to the server and parse its output var client = new net.Stream; parser(client).addListener('end', function (vars) { sys.puts(vars.moo); client.end(); }); client.connect(port); } serverSession(20801, ['\x00','\x04m','eow']); serverSession(20802, ['\x00\x00','\x12\x00\x00\x00happy pur','ring c','ats']); package/examples/simple_binary.js0000644000175000017500000000100411552674027017706 0ustar substacksubstack#!/usr/bin/env node var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var bufferList = new BufferList; var binary = Binary(bufferList) .getWord16be('xLen') .getBuffer('xs', 'xLen') .tap(function (vars) { vars.moo = 'xs:' + vars.xLen + ':' + vars.xs; }) .end() ; var buf = new Buffer(6); buf.write('\x00\x04meow', 'binary'); bufferList.push(buf); sys.puts(binary.vars.moo); // xs:4:meow package/examples/hackneyed.js0000644000175000017500000000064411552674027017015 0ustar substacksubstack#!/usr/bin/env node var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); var b = new BufferList; b.push(buf1,buf2,buf3); sys.puts(b.take(10)); // abcdexyz11 sys.puts(b.take(3)); // abc sys.puts(b.take(100)); // abcdexyz11358 package/examples/simple_bufferlist.js0000644000175000017500000000046511552674027020601 0ustar substacksubstack#!/usr/bin/env node var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var b = new BufferList; ['abcde','xyz','11358'].forEach(function (s) { var buf = new Buffer(s.length); buf.write(s); b.push(buf); }); sys.puts(b.take(10)); // abcdexyz11 package/test/binary_into.js0000644000175000017500000000250211552674027016533 0ustar substacksubstack// Check .into(), especially for object pollution var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); exports.into = function () { var bList = new BufferList; var tapped = false; Binary(bList) .getWord8('ones') .into('frac', function () { this .getWord64be('64') .getWord32be('32') .getWord16be('16') .getWord8('8') }) .tap(function (vars) { tapped = true; assert.eql(vars.ones, 3); assert.eql(vars.frac['64'], 73184615082362370); assert.eql(vars.frac['32'], 50661385); assert.eql(vars.frac['16'], 1801); assert.eql(vars.frac['8'], 3); assert.eql( Object.keys(vars).sort().join(' '), 'frac ones', 'object pollution with .into()' ) }) .end() ; var buf = new Buffer(16); var i = 0; String(4 * Math.atan2(1,1)).split('').forEach(function (digit) { if (digit != '.') { buf[i++] = parseInt(digit,10); } }); bList.push(buf); assert.ok(tapped, 'not tapped'); }; package/test/binary_endianness.js0000644000175000017500000001426611552674027017723 0ustar substacksubstack#!/usr/bin/env node // Test binary byte and endianness functions var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); exports.endianness = function () { var bList = new BufferList; Binary(bList) .getWord8('w8') .tap(function (vars) { assert.eql(vars.w8, 239, 'w8 is not 239') }) // 16 bit functions .getWord16le('w16le') .tap(function (vars) { assert.eql(vars.w16le, 23569, 'w16le is not 23569'); }) .getWord16be('w16be') .tap(function (vars) { assert.eql(vars.w16be, 23569, 'w16be is not 23569'); }) .getWord16les('w16les') .tap(function (vars) { assert.eql(vars.w16les, -239, 'w16les is not -239'); }) .getWord16bes('w16bes') .tap(function (vars) { assert.eql(vars.w16bes, -239, 'w16bes is not -239'); }) .getWord16les('w16lesu') .tap(function (vars) { assert.eql(vars.w16lesu, 23569, 'w16lesu is not -239'); }) .getWord16bes('w16besu') .tap(function (vars) { assert.eql(vars.w16besu, 23569, 'w16besu is not -239'); }) // 32 bit functions .getWord32le('w32le') .tap(function (vars) { assert.eql(vars.w32le, 287454020, 'w32le is not 287454020'); }) .getWord32be('w32be') .tap(function (vars) { assert.eql(vars.w32be, 287454020, 'w32be is not 287454020'); }) .getWord32les('w32les') .tap(function (vars) { assert.eql(vars.w32les, -16742383, 'w32les is not -16742383'); }) .getWord32bes('w32bes') .tap(function (vars) { assert.eql(vars.w32bes, -16742383, 'w32bes is not -16742383'); }) .getWord32les('w32lesu') .tap(function (vars) { assert.eql(vars.w32lesu, 2076074948, 'w32lesu is not 2076074948'); }) .getWord32bes('w32besu') .tap(function (vars) { assert.eql(vars.w32besu, 2076074948, 'w32besu is not 2076074948'); }) // 64 bit functions .getWord64le('w64le') .tap(function (vars) { assert.eql(vars.w64le, 9833440827789222417, 'w64le is not 9833440826932474692'); }) .getWord64be('w64be') .tap(function (vars) { assert.eql(vars.w64be, 9833440827789222417, 'w64be is not 9833440826932474692'); }) .getWord64les('w64les') .tap(function (vars) { assert.eql(vars.w64les, -8613303245920330000, 'w64les is not -8613303245920330000'); }) .getWord64bes('w64bes') .tap(function (vars) { assert.eql(vars.w64bes, -8613303245920330000, 'w64bes is not -8613303245920330000'); }) .getWord64les('w64lesu') .tap(function (vars) { assert.eql(vars.w64lesu, 5337084636995872375, 'w64lesu is not 5337084636995872375'); }) .getWord64bes('w64besu') .tap(function (vars) { assert.eql(vars.w64besu, 5337084636995872375, 'w64besu is not 5337084636995872375'); }) .end() ; var b8 = new Buffer(1); b8[0] = 239; bList.push(b8); // 16 bit functions var b16le = new Buffer(2); b16le[0] = 0x11; b16le[1] = 0x5C; bList.push(b16le); var b16be = new Buffer(2); b16be[0] = 0x5C; b16be[1] = 0x11; bList.push(b16be); var b16les = new Buffer(2); b16les[0] = 0x11; b16les[1] = 0xFF; bList.push(b16les); var b16bes = new Buffer(2); b16bes[0] = 0xFF; b16bes[1] = 0x11; bList.push(b16bes); var b16lesu = new Buffer(2); b16lesu[0] = 0x11; b16lesu[1] = 0x5C; bList.push(b16lesu); var b16besu = new Buffer(2); b16besu[0] = 0x5C; b16besu[1] = 0x11; bList.push(b16besu); // 32 bit functions var b32le = new Buffer(4); b32le[0] = 0x44; b32le[1] = 0x33; b32le[2] = 0x22; b32le[3] = 0x11; bList.push(b32le); var b32be = new Buffer(4); b32be[0] = 0x11; b32be[1] = 0x22; b32be[2] = 0x33; b32be[3] = 0x44; bList.push(b32be); var b32les = new Buffer(4); b32les[0] = 0x11; b32les[1] = 0x88; b32les[2] = 0x00; b32les[3] = 0xFF; bList.push(b32les); var b32bes = new Buffer(4); b32bes[0] = 0xFF; b32bes[1] = 0x00; b32bes[2] = 0x88; b32bes[3] = 0x11; bList.push(b32bes); var b32lesu = new Buffer(4); b32lesu[0] = 0xC4; b32lesu[1] = 0x63; b32lesu[2] = 0xBE; b32lesu[3] = 0x7B; bList.push(b32lesu); var b32besu = new Buffer(4); b32besu[0] = 0x7B; b32besu[1] = 0xBE; b32besu[2] = 0x63; b32besu[3] = 0xC4; bList.push(b32besu); // 64 bit functions var b64le = new Buffer(8); b64le[0] = 0x11; b64le[1] = 0x22; b64le[2] = 0x33; b64le[3] = 0x44; b64le[4] = 0x55; b64le[5] = 0x66; b64le[6] = 0x77; b64le[7] = 0x88; bList.push(b64le); var b64be = new Buffer(8); b64be[0] = 0x88; b64be[1] = 0x77; b64be[2] = 0x66; b64be[3] = 0x55; b64be[4] = 0x44; b64be[5] = 0x33; b64be[6] = 0x22; b64be[7] = 0x11; bList.push(b64be); var b64les = new Buffer(8); b64les[0] = 0x11; b64les[1] = 0x22; b64les[2] = 0x33; b64les[3] = 0x44; b64les[4] = 0x55; b64les[5] = 0x66; b64les[6] = 0x77; b64les[7] = 0x88; bList.push(b64les); var b64bes = new Buffer(8); b64bes[0] = 0x88; b64bes[1] = 0x77; b64bes[2] = 0x66; b64bes[3] = 0x55; b64bes[4] = 0x44; b64bes[5] = 0x33; b64bes[6] = 0x22; b64bes[7] = 0x11; bList.push(b64bes); var b64lesu = new Buffer(8); b64lesu[0] = 0x77; b64lesu[1] = 0x66; b64lesu[2] = 0x55; b64lesu[3] = 0x44; b64lesu[4] = 0x33; b64lesu[5] = 0x22; b64lesu[6] = 0x11; b64lesu[7] = 0x4A; bList.push(b64lesu); var b64besu = new Buffer(8); b64besu[0] = 0x4A; b64besu[1] = 0x11; b64besu[2] = 0x22; b64besu[3] = 0x33; b64besu[4] = 0x44; b64besu[5] = 0x55; b64besu[6] = 0x66; b64besu[7] = 0x77; bList.push(b64besu); }; package/test/binary_assign.js0000644000175000017500000000434311552674027017053 0ustar substacksubstack// Test .into and hierarchical addressing assignment var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); exports['binary assign'] = function () { var tapped = 0; var bList = new BufferList; Binary(bList) .getWord16be('foo','bar','baz') .tap(function (vars) { assert.eql( vars.foo.bar.baz, 24930, 'vars.foo.bar.baz != 24930, ' + 'vars.foo.bar.baz == ' + sys.inspect(vars.foo.bar.baz) ); tapped ++; }) .getWord32le(['one','two','three']) .tap(function (vars) { assert.eql( vars.one.two.three, 1717920867, 'vars.one.two.three != 1717920867, ' + 'vars.one.two.three == ' + sys.inspect(vars.one.two.three) ); tapped ++; }) .into(['what.the','fuck'],function () { this .getWord8('w') .getWord8('t') .getWord8('f') .getWord32le('?!') .tap(function (vars) { vars.meow = 9000; }) ; }) .tap(function (vars) { assert.eql( vars.what.the.fuck.w, 119, '.w != 119, .w == ' + vars.what.the.fuck.w ); assert.eql( vars.what.the.fuck.t, 116, '.t != 119, .t == ' + vars.what.the.fuck.t ); assert.eql( vars.what.the.fuck.f, 102, '.f != 119, .f == ' + vars.what.the.fuck.f ); assert.eql( vars.what.the.fuck['?!'], 825303359, '.?! != 825303359, .?! == ' + vars.what.the.fuck['?!'] ); assert.eql( vars.what.the.fuck['meow'], 9000, '.meow != 9000, .meow == ' + vars.what.the.fuck.meow ); tapped ++; }) .end() ; var buf = new Buffer(13); buf.write('abcdefwtf?!11'); bList.push(buf); assert.eql(tapped, 3, 'tapped != 3, tapped == ' + tapped); }; package/test/binary_event.js0000644000175000017500000000352011552674027016704 0ustar substacksubstackvar sys = require('sys'); var net = require('net'); var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); function parser (sock) { var bufferList = new BufferList; sys.pump(sock, bufferList); return Binary(bufferList) .getWord16be('xLen') .when('xLen', 0, function (vars) { this .getWord32le('msgLen') .getBuffer('msg', 'msgLen') .tap(function (vars) { vars.moo = 'msg:' + vars.msgLen + ':' + vars.msg; }) .exit() ; }) .getBuffer('xs', 'xLen') .tap(function (vars) { vars.moo = 'xs:' + vars.xLen + ':' + vars.xs; }) .end() ; } exports['binary event'] = function () { function serverSession (port, strings, moo) { // fire up a server to write the strings when a client connects var server = net.createServer(function (stream) { strings.forEach(function (s) { stream.write(s); }); stream.end(); server.close(); }); server.listen(port); // connect to the server and parse its output var client = new net.Stream; parser(client).on('end', function (vars) { assert.eql( moo, vars.moo, 'moo != ' + sys.inspect(moo) + ', moo == ' + sys.inspect(vars.moo) ); client.end(); }); setTimeout(function () { client.connect(port); }, 50); } serverSession(20801, ['\x00','\x04m','eow'], 'xs:4:meow' ); serverSession(20802, ['\x00\x00','\x12\x00\x00\x00happy pur','ring c','ats'], 'msg:18:happy purring cats' ); }; package/test/event.js0000644000175000017500000000232111552674027015336 0ustar substacksubstack#!/usr/bin/env node // Test joining lots of chunks into one buffer var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var assert = require('assert'); exports.events = function () { var b = new BufferList({ encoding: 'binary' }); var times = 0; var wrote = null; b.addListener('write', function (buf) { assert.eql( wrote.toString(), buf.toString(), 'write callback gives its arguments' ); times ++; }); var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); var wrote = buf1; b.write(buf1); var wrote = buf2; b.write(buf2); assert.eql(times, 2, 'wrote twice'); var wrote = buf3; b.write(buf3); assert.eql(times, 3, 'wrote thrice'); assert.eql(b.take(), 'abcdexyz11358', 'entire buffer check'); var advanced = 0; b.on('advance', function (n) { assert.eql(n, 3, 'n = 3 in advance callback') advanced ++; }); b.advance(3); assert.eql(b.take(3), 'dex', 'advanced 3'); assert.eql(advanced, 1, 'advance callback triggered once'); }; package/test/binary.js0000644000175000017500000000503411552674027015505 0ustar substacksubstack// Test the binary interface to bufferlists var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist').BufferList; // old style var Binary = require('bufferlist/binary').Binary; // old style var sys = require('sys'); var assert = require('assert'); exports.binary = function () { function runTest(bufs, check) { var bList = new BufferList; var binary = Binary(bList) .getWord16be('xLen') .when('xLen', 0, function (vars) { assert.eql(vars.xLen, 0, 'when check for 0 failed'); this .getWord32le('msgLen') .getBuffer('msg', function (vars) { return vars.msgLen }) .tap(function (vars) { vars.moo = 42; }) .exit() ; }) .getBuffer('xs', 'xLen') .tap(function (vars) { vars.moo = 100; }) .end() ; var iv = setInterval(function () { var buf = bufs.shift(); if (!buf) { clearInterval(iv); check(binary.vars); } else { bList.push(buf); } }, 50); } runTest( ['\x00','\x04m','eow'].map(function (s) { var b = new Buffer(Buffer.byteLength(s,'binary')); b.write(s,'binary'); return b; }), function (vars) { assert.eql( vars.xLen, 4, 'xLen == 4 failed (xLen == ' + sys.inspect(vars.xLen) + ')' ); var xs = vars.xs.toString(); assert.eql( xs, 'meow', 'xs != "meow", xs = ' + sys.inspect(xs) ); assert.eql( vars.moo, 100, 'moo != 100, moo == ' + sys.inspect(vars.moo) ); } ); runTest( ['\x00\x00','\x12\x00\x00\x00hap','py pur','ring c','ats'] .map(function (s) { var b = new Buffer(Buffer.byteLength(s,'binary')); b.write(s,'binary'); return b; }), function (vars) { assert.eql(vars.xLen, 0, 'xLen == 0 in "\\x00\\x12happy purring cats"'); assert.eql( vars.msgLen, 18, 'msgLen != 18, msgLen = ' + sys.inspect(vars.msgLen) ); assert.eql(vars.moo, 42, 'moo != 42'); } ); }; package/test/take.js0000644000175000017500000000156211552674027015147 0ustar substacksubstack// Test BufferList#take(). var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var assert = require('assert'); exports.join = function () { var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); var b = new BufferList; b.push(buf1,buf2,buf3); assert.eql( b.take('binary'), 'abcdexyz11358', 'take entire BufferList at once' ); assert.eql( b.take(1, 'ascii'), 'a', 'take 1 byte with "ascii" encoding' ); assert.ok( Buffer.isBuffer(b.take(1)), 'take without encoding returns Buffer' ); // Now set the encoding b.encoding = 'ascii'; assert.ok( !Buffer.isBuffer(b.take(1)), 'take with encoding returns String' ); }; package/test/client_server.js0000644000175000017500000000301211552674027017057 0ustar substacksubstack// Test a client/server interaction // If nothing gets printed, everything is fine. var sys = require('util'); var net = require('net'); var client = new net.Stream; var assert = require('assert'); exports['client/server'] = function () { var BufferList = require('bufferlist'); var bufs = new BufferList({ encoding: 'binary' }); var elems = []; client.addListener('data', function (data) { bufs.push(data); elems.push(data); assert.eql(bufs.take(3).toString(), elems[0].toString(), 'take first 3 bytes ('+sys.inspect(elems[0])+') vs ('+sys.inspect(bufs.take(3).toString())+')'); assert.eql(bufs.take(100), elems.join(''), 'take past length of buffer'); }); client.addListener('end', function (data) { assert.eql(bufs.length, elems.join('').length, 'verify length'); assert.eql(bufs.take(bufs.length), elems.join(''), 'take to the end'); client.end(); }); var port = 1e4 + Math.random() * ((1 << 16) - 1 - 1e4); var server = net.createServer(function (stream) { stream.addListener('connect', function () { stream.write('foo'); setTimeout(function () { stream.write('bar'); setTimeout(function () { stream.write('baz'); stream.end(); server.close(); }, 500); }, 500); }); }); server.listen(port); setTimeout(function () { client.connect(port); }, 50); }; package/test/advance.js0000644000175000017500000000162511552674027015624 0ustar substacksubstack// Test advancing the buffer var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var assert = require('assert'); exports.advance = function () { var b = new BufferList({ encoding: 'binary' }); var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); b.write(buf1); assert.eql(b.take(b.length), 'abcde', 'wrote correctly'); b.advance(3); assert.eql(b.take(b.length), 'de', 'advanced with one buffer'); b.advance(3); assert.eql(b.take(b.length), '', 'advanced one buffer past the end'); b.write(buf2); assert.eql(b.take(b.length), 'yz', 'offset preserved past the end'); b.write(buf3); assert.eql(b.take(b.length), 'yz11358', 'second write after advance'); b.advance(4); assert.eql(b.take(b.length), '358', 'advance after two writes'); }; package/test/binary_loop.js0000644000175000017500000000706011552674027016537 0ustar substacksubstack// Test binary looping functions var sys = require('sys'); var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); exports['binary loop'] = function () { // test repeat var reps = 0; var trickyList = []; Binary(new BufferList) .repeat(5000, function(vars, n) { reps++; }) .tap(function (vars) { assert.eql( reps, 5000, 'reps != 5000, reps == ' + reps + ' in repeat test' ); }) .repeat(3, function (vars, i) { this .repeat(4, function (vars, j) { trickyList.push([ i + 1, j + 1 ]); }) ; }) .tap(function (vars) { expectedTrickyList = [ [1,1],[1,2],[1,3],[1,4], [2,1],[2,2],[2,3],[2,4], [3,1],[3,2],[3,3],[3,4] ]; for (var i = 0; i < trickyList.length; i++) { assert.eql( trickyList[i][0], expectedTrickyList[i][0], 'trickly list is not what it should be. it should be: ' + sys.inspect(expectedTrickyList) + '. it is: ' + sys.inspect(trickyList) ); assert.eql( trickyList[i][1], expectedTrickyList[i][1], 'trickly list is not what it should be. it should be: ' + sys.inspect(expectedTrickyList) + '. it is: ' + sys.inspect(trickyList) ); } }) .end() ; assert.eql(reps, 5000, 'reps != 5000, reps == ' + reps + ' in outer repeat check'); var bufferList = new BufferList; var loops = 0; Binary(bufferList) .forever(function () { this .getWord16be('moo','count') .tap(function (vars) { assert.eql( vars.moo.count, 100, 'count != 100, count == ' + vars.moo.count ); vars.reps = 0; }) .repeat('moo.count', function (vars, i) { this .getWord16be('size') .tap(function (vars) { assert.eql( vars.size, 1000, 'size != 1000, size == ' + vars.size ); }) .getBuffer('block', 'size') ; vars.reps ++; }) .tap(function (vars) { assert.eql( vars.reps, 100, 'reps != 100, reps == ' + vars.reps ); }) ; loops ++; if (loops == 20) this.exit(); }) .end() ; for (var n = 0; n < 20; n++) { var countBuf = new Buffer(2); countBuf[0] = 100 >> 8; countBuf[1] = 100 % 256; bufferList.push(countBuf); for (var i = 0; i < 100; i++) { var buf = new Buffer(1000 + 2); buf[0] = 1000 >> 8; buf[1] = 1000 % 256; for (var j = 0; j < 1000; j++) { buf[j + 2] = j; } bufferList.push(buf); } } assert.eql(loops, 20, 'loops != 20, loops == ' + loops); }; package/test/join.js0000644000175000017500000000120711552674027015156 0ustar substacksubstack// Test joining lots of chunks into one buffer var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var assert = require('assert'); exports.join = function () { var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); var b = new BufferList; b.push(buf1,buf2,buf3); assert.eql( b.join().toString('ascii',0,b.length), 'abcdexyz11358', 'join multiple chunks into one Buffer' ); assert.eql( b.join(3,6).toString(), 'dex', 'slice of a buffer join' ); }; package/test/binary_jump.js0000644000175000017500000000245011552674027016537 0ustar substacksubstack// Jumping around in a binary parser var Buffer = require('buffer').Buffer; var BufferList = require('bufferlist'); var Binary = require('bufferlist/binary'); var assert = require('assert'); Number.prototype.upTo = function (n) { var acc = []; for (var i = Number(this); i <= n; i++) { acc.push(i); } return acc; }; Number.prototype.downTo = function (n) { var acc = []; for (var i = Number(this); i >= n; i--) { acc.push(i); } return acc; }; Array.prototype.zip = function (xs) { var arr = this; return (0).upTo(this.length - 1).map(function (i) { return [ arr[i], xs[i] ]; }); }; exports.jump = function () { var tapped = 0; var bList = new BufferList; Binary(bList) .skip(3) .getWord16be('de') .tap(function (vars) { var de = 256 * 'd'.charCodeAt(0) + 'e'.charCodeAt(0); assert.eql( vars.de, de, 'getWord16be at 3 should be ' + de + ', not ' + vars.de ); tapped ++; }) .end() ; var buf1 = new Buffer(5); buf1.write('abcde'); var buf2 = new Buffer(3); buf2.write('xyz'); var buf3 = new Buffer(5); buf3.write('11358'); bList.push(buf1,buf2,buf3); assert.eql(tapped, 1, 'not tapped'); };