1// Copyright 2015 Joyent, Inc. 2 3module.exports = SSHBuffer; 4 5var assert = require('assert-plus'); 6var Buffer = require('safer-buffer').Buffer; 7 8function SSHBuffer(opts) { 9 assert.object(opts, 'options'); 10 if (opts.buffer !== undefined) 11 assert.buffer(opts.buffer, 'options.buffer'); 12 13 this._size = opts.buffer ? opts.buffer.length : 1024; 14 this._buffer = opts.buffer || Buffer.alloc(this._size); 15 this._offset = 0; 16} 17 18SSHBuffer.prototype.toBuffer = function () { 19 return (this._buffer.slice(0, this._offset)); 20}; 21 22SSHBuffer.prototype.atEnd = function () { 23 return (this._offset >= this._buffer.length); 24}; 25 26SSHBuffer.prototype.remainder = function () { 27 return (this._buffer.slice(this._offset)); 28}; 29 30SSHBuffer.prototype.skip = function (n) { 31 this._offset += n; 32}; 33 34SSHBuffer.prototype.expand = function () { 35 this._size *= 2; 36 var buf = Buffer.alloc(this._size); 37 this._buffer.copy(buf, 0); 38 this._buffer = buf; 39}; 40 41SSHBuffer.prototype.readPart = function () { 42 return ({data: this.readBuffer()}); 43}; 44 45SSHBuffer.prototype.readBuffer = function () { 46 var len = this._buffer.readUInt32BE(this._offset); 47 this._offset += 4; 48 assert.ok(this._offset + len <= this._buffer.length, 49 'length out of bounds at +0x' + this._offset.toString(16) + 50 ' (data truncated?)'); 51 var buf = this._buffer.slice(this._offset, this._offset + len); 52 this._offset += len; 53 return (buf); 54}; 55 56SSHBuffer.prototype.readString = function () { 57 return (this.readBuffer().toString()); 58}; 59 60SSHBuffer.prototype.readCString = function () { 61 var offset = this._offset; 62 while (offset < this._buffer.length && 63 this._buffer[offset] !== 0x00) 64 offset++; 65 assert.ok(offset < this._buffer.length, 'c string does not terminate'); 66 var str = this._buffer.slice(this._offset, offset).toString(); 67 this._offset = offset + 1; 68 return (str); 69}; 70 71SSHBuffer.prototype.readInt = function () { 72 var v = this._buffer.readUInt32BE(this._offset); 73 this._offset += 4; 74 return (v); 75}; 76 77SSHBuffer.prototype.readInt64 = function () { 78 assert.ok(this._offset + 8 < this._buffer.length, 79 'buffer not long enough to read Int64'); 80 var v = this._buffer.slice(this._offset, this._offset + 8); 81 this._offset += 8; 82 return (v); 83}; 84 85SSHBuffer.prototype.readChar = function () { 86 var v = this._buffer[this._offset++]; 87 return (v); 88}; 89 90SSHBuffer.prototype.writeBuffer = function (buf) { 91 while (this._offset + 4 + buf.length > this._size) 92 this.expand(); 93 this._buffer.writeUInt32BE(buf.length, this._offset); 94 this._offset += 4; 95 buf.copy(this._buffer, this._offset); 96 this._offset += buf.length; 97}; 98 99SSHBuffer.prototype.writeString = function (str) { 100 this.writeBuffer(Buffer.from(str, 'utf8')); 101}; 102 103SSHBuffer.prototype.writeCString = function (str) { 104 while (this._offset + 1 + str.length > this._size) 105 this.expand(); 106 this._buffer.write(str, this._offset); 107 this._offset += str.length; 108 this._buffer[this._offset++] = 0; 109}; 110 111SSHBuffer.prototype.writeInt = function (v) { 112 while (this._offset + 4 > this._size) 113 this.expand(); 114 this._buffer.writeUInt32BE(v, this._offset); 115 this._offset += 4; 116}; 117 118SSHBuffer.prototype.writeInt64 = function (v) { 119 assert.buffer(v, 'value'); 120 if (v.length > 8) { 121 var lead = v.slice(0, v.length - 8); 122 for (var i = 0; i < lead.length; ++i) { 123 assert.strictEqual(lead[i], 0, 124 'must fit in 64 bits of precision'); 125 } 126 v = v.slice(v.length - 8, v.length); 127 } 128 while (this._offset + 8 > this._size) 129 this.expand(); 130 v.copy(this._buffer, this._offset); 131 this._offset += 8; 132}; 133 134SSHBuffer.prototype.writeChar = function (v) { 135 while (this._offset + 1 > this._size) 136 this.expand(); 137 this._buffer[this._offset++] = v; 138}; 139 140SSHBuffer.prototype.writePart = function (p) { 141 this.writeBuffer(p.data); 142}; 143 144SSHBuffer.prototype.write = function (buf) { 145 while (this._offset + buf.length > this._size) 146 this.expand(); 147 buf.copy(this._buffer, this._offset); 148 this._offset += buf.length; 149}; 150