UNPKG

bin-protocol

Version:

buffer maker and parser for binary protocols

278 lines (245 loc) 7.57 kB
'use strict'; var Long = require('long'); var varint = require('./protobuf/varint'); var Reader = require('./reader'); var Writer = require('./writer'); var _ = require('lodash'); var util = require('util'); var primitives = [ ['Int8', 1], ['UInt8', 1], ['Int16LE', 2], ['UInt16LE', 2], ['Int16BE', 2], ['UInt16BE', 2], ['Int32LE', 4], ['Int32BE', 4], ['UInt32LE', 4], ['UInt32BE', 4], ['FloatLE', 4], ['FloatBE', 4], ['DoubleLE', 8], ['DoubleBE', 8] ]; function Protocol() {} Protocol.Reader_ = Reader; Protocol.Writer_ = Writer; Protocol.prototype.define = function (name, config, namespace) { if (config.read) { this.reader.define(name, config.read, namespace); } if (config.write) { this.writer.define(name, config.write, namespace); } }; Protocol.prototype.read = function (buffer) { return this.reader.reset(buffer); }; Protocol.prototype.write = function () { return this.writer.reset(); }; function define(name, config, namespace) { Reader.define(name, config.read, namespace); Writer.define(name, config.write, namespace); } function createProtocol(_SuperProtocol, constructor) { function _Reader() { Reader.apply(this, arguments); } function _Writer() { Writer.apply(this, arguments); } function _P(options) { this.options = options || {}; this.reader = new _Reader(this.options); this.writer = new _Writer(this.options); if (typeof constructor === 'function') { constructor.call(this); } } _P.Reader_ = _Reader; _P.Writer_ = _Writer; util.inherits(_P, _SuperProtocol); util.inherits(_Reader, _SuperProtocol.Reader_); util.inherits(_Writer, _SuperProtocol.Writer_); _Reader.prototype.__methods = _SuperProtocol.Reader_.prototype.__methods.slice(); _Writer.prototype.__methods = _SuperProtocol.Writer_.prototype.__methods.slice(); _P.define = function (name, config, namespace) { if (config.read) { Reader.define(name, config.read, namespace, _Reader); } if (config.write) { Writer.define(name, config.write, namespace, _Writer); } }; _P.createProtocol = _.partial(createProtocol, _P); return _P; } primitives.forEach(function (p) { define(p[0], { read: function () { var r = this.buffer['read' + p[0]](this.offset); this.offset += p[1]; return r; }, write: function (value) { var r; this.demand(p[1]); r = this.buffer['write' + p[0]](value, this.offset); this.offset += p[1]; return r; } }); }); define('raw', { read: function (bytes) { var r; this.demand(bytes); r = new Buffer(bytes); this.buffer.copy(r, 0, this.offset, this.offset + bytes); this.offset += bytes; return r; }, write: function (buffer) { if (typeof buffer === 'string' || Array.isArray(buffer)) { buffer = new Buffer(buffer); } this.demand(buffer.length); buffer.copy(this.buffer, this.offset, 0); this.offset += buffer.length; } }); define('Int64BE', { read: function () { var l = new Long(this.buffer.readInt32BE(this.offset + 4), this.buffer.readInt32BE(this.offset)); this.offset += 8; return l; }, write: function (value) { this.demand(8); value = Long.fromValue(value); this.buffer.writeInt32BE(value.getHighBits(), this.offset); this.buffer.writeInt32BE(value.getLowBits(), this.offset + 4); this.offset += 8; } }); define('Int64LE', { read: function () { var l = new Long(this.buffer.readInt32LE(this.offset), this.buffer.readInt32LE(this.offset + 4)); this.offset += 8; return l; }, write: function (value) { this.demand(8); value = Long.fromValue(value); this.buffer.writeInt32LE(value.getHighBits(), this.offset + 4); this.buffer.writeInt32LE(value.getLowBits(), this.offset); this.offset += 8; } }); define('UInt64BE', { read: function () { var l = new Long(this.buffer.readUInt32BE(this.offset + 4), this.buffer.readUInt32BE(this.offset), true); this.offset += 8; return l; }, write: function (value) { this.demand(8); value = Long.fromValue(value); this.buffer.writeUInt32BE(value.getHighBitsUnsigned(), this.offset); this.buffer.writeUInt32BE(value.getLowBitsUnsigned(), this.offset + 4); this.offset += 8; } }); define('UInt64LE', { read: function () { var l = new Long(this.buffer.readUInt32LE(this.offset), this.buffer.readUInt32LE(this.offset + 4), true); this.offset += 8; return l; }, write: function (value) { this.demand(8); value = Long.fromValue(value); this.buffer.writeUInt32LE(value.getHighBitsUnsigned(), this.offset + 4); this.buffer.writeUInt32LE(value.getLowBitsUnsigned(), this.offset); this.offset += 8; } }); // unsigned varint define('UVarint', { read: function () { var v = varint.read(this.buffer, this.offset); this.offset += v.length; return v.value; }, write: function (value) { this.demand(5); this.offset += varint.write(this.buffer, value, this.offset); } }); // normal signed varint define('Varint', { read: function () { return this.UVarint().context | 0; }, // should be 10 bytes long // https://developers.google.com/protocol-buffers/docs/encoding?hl=en#signed-integers // Quote: "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes long – it is, // effectively, treated like a very large unsigned integer. // If you use one of the signed types, the resulting varint uses ZigZag encoding, which is much more efficient." write: function (value) { if (value < 0) { this.demand(10); this.UVarint64(value); } else { this.demand(5); this.UVarint(value); } } }); // zigzag encoded signed varint define('SVarint', { read: function () { return varint.dezigzag(this.UVarint().context); }, write: function (value) { this.demand(5); this.UVarint(varint.zigzag(value)); } }); // unsigned varint 64 bit define('UVarint64', { read: function () { var v = varint.read64(this.buffer, this.offset); this.offset += v.length; return v.value; }, write: function (value) { this.demand(10); value = Long.fromValue(value); this.offset += varint.write64(this.buffer, value, this.offset); } }); // normal signed varint 64 bit define('Varint64', { read: function () { return this.UVarint64().context.toSigned(); }, write: function (value) { this.demand(10); this.UVarint64(value); } }); // zigzag encoded signed varint 64 define('SVarint64', { read: function () { return varint.dezigzag64(this.UVarint64().context); }, write: function (value) { this.demand(10); value = Long.fromValue(value); this.UVarint64(varint.zigzag64(value)); } }); module.exports = createProtocol(Protocol); module.exports.createProtobufProtocol = require('./protobuf');