From 50e147bd03a9e2d722e2d7fc96adf8ccefe49866 Mon Sep 17 00:00:00 2001 From: koichik Date: Fri, 22 Jul 2011 02:53:11 +0900 Subject: [PATCH] Add an optional length argument to Buffer.write() Fixes #243. Fixes #1361. --- doc/api/buffers.markdown | 10 ++-- lib/buffer.js | 98 +++++++++++++++++++++++++++----------- test/simple/test-buffer.js | 47 ++++++++++++++++++ 3 files changed, 122 insertions(+), 33 deletions(-) diff --git a/doc/api/buffers.markdown b/doc/api/buffers.markdown index ae24855fb60..2183e006ddb 100644 --- a/doc/api/buffers.markdown +++ b/doc/api/buffers.markdown @@ -47,12 +47,12 @@ Allocates a new buffer using an `array` of octets. Allocates a new buffer containing the given `str`. -### buffer.write(string, offset=0, encoding='utf8') +### buffer.write(string, offset=0, length=buffer.length-offset, encoding='utf8') -Writes `string` to the buffer at `offset` using the given encoding. Returns -number of octets written. If `buffer` did not contain enough space to fit -the entire string, it will write a partial amount of the string. -The method will not write partial characters. +Writes `string` to the buffer at `offset` using the given encoding. `length` is +the number of bytes to write. Returns number of octets written. If `buffer` did +not contain enough space to fit the entire string, it will write a partial +amount of the string. The method will not write partial characters. Example: write a utf8 string into a buffer, then print it diff --git a/lib/buffer.js b/lib/buffer.js index b3b0b5446f3..f31d69e85c6 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -92,15 +92,27 @@ SlowBuffer.prototype.toString = function(encoding, start, end) { }; -SlowBuffer.prototype.hexWrite = function(string, offset) { - var len = string.length; +SlowBuffer.prototype.hexWrite = function(string, offset, length) { offset = +offset || 0; + var remaining = this.length - offset; + if (!length) { + length = remaining; + } else { + length = +length; + if (length > remaining) { + length = remaining; + } + } // must be an even number of digits - if (len % 2) { + var strLen = string.length; + if (strLen % 2) { throw new Error('Invalid hex string'); } - for (var i = 0; i < len / 2; i++) { + if (length > strLen / 2) { + length = strLen / 2; + } + for (var i = 0; i < length; i++) { var byte = parseInt(string.substr(i * 2, 2), 16); if (isNaN(byte)) throw new Error('Invalid hex string'); this[offset + i] = byte; @@ -109,38 +121,53 @@ SlowBuffer.prototype.hexWrite = function(string, offset) { }; -SlowBuffer.prototype.write = function(string, offset, encoding) { - // Support both (string, offset, encoding) - // and the legacy (string, encoding, offset) - if (!isFinite(offset)) { +SlowBuffer.prototype.write = function(string, offset, length, encoding) { + // Support both (string, offset, length, encoding) + // and the legacy (string, encoding, offset, length) + if (isFinite(offset)) { + if (!isFinite(length)) { + encoding = length; + length = undefined; + } + } else { // legacy var swap = encoding; encoding = offset; - offset = swap; + offset = length; + length = swap; } offset = +offset || 0; + var remaining = this.length - offset; + if (!length) { + length = remaining; + } else { + length = +length; + if (length > remaining) { + length = remaining; + } + } encoding = String(encoding || 'utf8').toLowerCase(); switch (encoding) { case 'hex': - return this.hexWrite(string, offset); + return this.hexWrite(string, offset, length); case 'utf8': case 'utf-8': - return this.utf8Write(string, offset); + return this.utf8Write(string, offset, length); case 'ascii': - return this.asciiWrite(string, offset); + return this.asciiWrite(string, offset, length); case 'binary': - return this.binaryWrite(string, offset); + return this.binaryWrite(string, offset, length); case 'base64': - return this.base64Write(string, offset); + return this.base64Write(string, offset, length); case 'ucs2': case 'ucs-2': - return this.ucs2Write(string, offset); + return this.ucs2Write(string, offset, length); default: throw new Error('Unknown encoding'); @@ -271,47 +298,61 @@ Buffer.prototype.set = function set(i, v) { }; -// write(string, offset = 0, encoding = 'utf8') -Buffer.prototype.write = function(string, offset, encoding) { - if (!isFinite(offset)) { +// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8') +Buffer.prototype.write = function(string, offset, length, encoding) { + // Support both (string, offset, length, encoding) + // and the legacy (string, encoding, offset, length) + if (isFinite(offset)) { + if (!isFinite(length)) { + encoding = length; + length = undefined; + } + } else { // legacy var swap = encoding; encoding = offset; - offset = swap; + offset = length; + length = swap; } offset = +offset || 0; + var remaining = this.length - offset; + if (!length) { + length = remaining; + } else { + length = +length; + if (length > remaining) { + length = remaining; + } + } encoding = String(encoding || 'utf8').toLowerCase(); - // Make sure we are not going to overflow - var maxLength = this.length - offset; - var ret; switch (encoding) { case 'hex': - ret = this.parent.hexWrite(string, this.offset + offset, maxLength); + ret = this.parent.hexWrite(string, this.offset + offset, length); break; case 'utf8': case 'utf-8': - ret = this.parent.utf8Write(string, this.offset + offset, maxLength); + ret = this.parent.utf8Write(string, this.offset + offset, length); break; case 'ascii': - ret = this.parent.asciiWrite(string, this.offset + offset, maxLength); + ret = this.parent.asciiWrite(string, this.offset + offset, length); break; case 'binary': - ret = this.parent.binaryWrite(string, this.offset + offset, maxLength); + ret = this.parent.binaryWrite(string, this.offset + offset, length); break; case 'base64': // Warning: maxLength not taken into account in base64Write - ret = this.parent.base64Write(string, this.offset + offset, maxLength); + ret = this.parent.base64Write(string, this.offset + offset, length); break; case 'ucs2': case 'ucs-2': - ret = this.parent.ucs2Write(string, this.offset + offset, maxLength); + ret = this.parent.ucs2Write(string, this.offset + offset, length); break; default: @@ -1019,3 +1060,4 @@ Buffer.prototype.writeDouble = function(value, offset, endian) { verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); IEEE754.writeIEEE754(buffer, value, offset, endian, 52, 8); }; + diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 9cd4959aa2c..8c0d4fb0ddf 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -621,3 +621,50 @@ assert.equal(written, 9); written = buf.write('あいう\0'); // 3bytes * 3 + 1byte assert.equal(written, 10); +// #243 Test write() with maxLength +var buf = new Buffer(4); +buf.fill(0xFF); +var written = buf.write('abcd', 1, 2, 'utf8'); +console.log(buf); +assert.equal(written, 2); +assert.equal(buf[0], 0xFF); +assert.equal(buf[1], 0x61); +assert.equal(buf[2], 0x62); +assert.equal(buf[3], 0xFF); + +buf.fill(0xFF); +written = buf.write('abcd', 1, 4); +console.log(buf); +assert.equal(written, 3); +assert.equal(buf[0], 0xFF); +assert.equal(buf[1], 0x61); +assert.equal(buf[2], 0x62); +assert.equal(buf[3], 0x63); + +buf.fill(0xFF); +written = buf.write('abcd', 'utf8', 1, 2); // legacy style +console.log(buf); +assert.equal(written, 2); +assert.equal(buf[0], 0xFF); +assert.equal(buf[1], 0x61); +assert.equal(buf[2], 0x62); +assert.equal(buf[3], 0xFF); + +buf.fill(0xFF); +written = buf.write('abcdef', 1, 2, 'hex'); +console.log(buf); +assert.equal(written, 2); +assert.equal(buf[0], 0xFF); +assert.equal(buf[1], 0xAB); +assert.equal(buf[2], 0xCD); +assert.equal(buf[3], 0xFF); + +buf.fill(0xFF); +written = buf.write('abcd', 0, 2, 'ucs2'); +console.log(buf); +assert.equal(written, 2); +assert.equal(buf[0], 0x61); +assert.equal(buf[1], 0x00); +assert.equal(buf[2], 0xFF); +assert.equal(buf[3], 0xFF); +