Permalink
Browse files

Support serialization to Buffer objects.

  • Loading branch information...
1 parent c0ff1ea commit f659aa5d3c57cdd718332cbb76a0827cf6d3faa2 @pgriess committed Jul 14, 2010
Showing with 91 additions and 35 deletions.
  1. +7 −1 README.md
  2. +52 −34 lib/ns.js
  3. +32 −0 test/test.js
View
@@ -2,6 +2,11 @@ A braindead module for reading and writing
[netstrings](http://cr.yp.to/proto/netstrings.txt).
## API
+ nsWriteLength(len)
+
+Compute the number of bytes to required serialize a netstring with the `len`
+bytes.
+
nsWrite(pay, payStart = 0, payEnd = pay.length, buf = undefined, bufOff = 0)
Write the payload `pay ` out in netstring format, returning a string. The
@@ -12,7 +17,8 @@ string or a `Buffer` object.
If the `buf` parameter is specified, the netstring is written to this buffer
rather than returned as a string. The `bufOff` parameter allows specifying
-the offset into the buffer at which to begin writing.
+the offset into the buffer at which to begin writing. The length of the
+resulting netstring in bytes is returned.
nsPayload(buf, off = 0)
View
@@ -1,7 +1,7 @@
// An implementation of the http://cr.yp.to/proto/netstrings.txt format.
var assert = require('assert');
-var sys = require('sys');
+var Buffer = require('buffer').Buffer;
// Get the length of the netstring payload (i.e. excluding header and footer)
// pointed to by Buffer or String 'buf'. Returns -1 if the buffer is
@@ -53,7 +53,7 @@ exports.nsPayloadLength = nsPayloadLength;
// pointed to by Buffer or String 'buf'. Negative return values are the same
// as length().
var nsLength = function(buf, off) {
- return nsLengthFromLength(nsPayloadLength(buf, off));
+ return nsWriteLength(nsPayloadLength(buf, off));
};
exports.nsLength = nsLength;
@@ -68,9 +68,7 @@ var nsPayload = function(buf, off) {
return len;
}
- var nsLen = nsLengthFromLength(len);
-
- // sys.puts('len=' + len + '; nsLen=' + nsLen + '; buf.length=' + buf.length + '; off=' + off);
+ var nsLen = nsWriteLength(len);
// We don't have the entire buffer yet
if (buf.length - off - nsLen < 0) {
@@ -87,6 +85,28 @@ var nsPayload = function(buf, off) {
};
exports.nsPayload = nsPayload;
+// Get the length of teh netstring that would result if writing the given
+// number of bytes.
+var nsWriteLength = function(len) {
+ // Negative values are special (see nsPayloadLength()); just return it
+ if (len < 0) {
+ return len;
+ }
+
+ // Compute the number of digits in the length specifier. Stop at
+ // any value < 10 and just add 1 later (this catches the case where
+ // '0' requires a digit.
+ nslen = len;
+ while (len >= 10) {
+ nslen += 1;
+ len /= 10;
+ }
+
+ // nslen + 1 (last digit) + 1 (:) + 1 (,)
+ return nslen + 3;
+};
+exports.nsWriteLength = nsWriteLength;
+
// Write the given payload to a netstring.
//
// All parameters other than 'pay' are optional; 'pay' itself can be either a
@@ -114,43 +134,41 @@ var nsWrite = function(pay, payStart, payEnd, buf, bufOff) {
throw new Error('payEnd is out of bounds');
}
- var slice = (typeof pay === 'string') ?
- function (start, end) {
- return pay.substring(start, end);
- } :
- function (start, end) {
- return pay.slice(start, end).toString('utf-8');
- };
+ // Normalize our input into a UTF-8 encoded buffer
+ //
+ // XXX: Submit patch for new Buffer('');
+ if (typeof pay === 'string') {
+ pay = (payStart == payEnd) ?
+ new Buffer(0) :
+ new Buffer(pay.substring(payStart, payEnd));
+ payStart = 0;
+ payEnd = pay.length;
+ }
+
+ assert.equal(typeof pay, 'object');
if (buf) {
if (typeof buf !== 'object') {
throw new Error('The \'buf\' parameter must be a Buffer');
}
- throw new Error('Writing to a Buffer not yet implemented');
- } else {
- return (payEnd - payStart) + ':' + slice(payStart, payEnd) + ',';
- }
-};
-exports.nsWrite = nsWrite;
+ var len = payEnd - payStart;
+ var nsLen = nsWriteLength(len);
+ var hdrLen = nsLen - len - 1;
-// Internal APIs
+ if (buf.length - bufOff < nsLen) {
+ throw new Error('Target buffer does not have enough space');
+ }
-var nsLengthFromLength = function(len) {
- // Negative values are special (see nsPayloadLength()); just return it
- if (len < 0) {
- return len;
- }
+ buf.write(len + ':', bufOff);
+ pay.copy(buf, bufOff + hdrLen, payStart, payEnd);
+ buf.write(',', bufOff + nsLen - 1);
- // Compute the number of digits in the length specifier. Stop at
- // any value < 10 and just add 1 later (this catches the case where
- // '0' requires a digit.
- nslen = len;
- while (len >= 10) {
- nslen += 1;
- len /= 10;
+ return nsLen;
+ } else {
+ return (payEnd - payStart) + ':' +
+ pay.slice(payStart, payEnd).toString() +
+ ',';
}
-
- // nslen + 1 (last digit) + 1 (:) + 1 (,)
- return nslen + 3;
};
+exports.nsWrite = nsWrite;
View
@@ -58,6 +58,21 @@ var ns = require('../lib/ns');
})();
(function() {
+ var ts = new at.TestSuite('nsWriteLength');
+
+ ts.addTests({
+ 'simple' : function(as) {
+ as.equal(ns.nsWriteLength(0), 3);
+ as.equal(ns.nsWriteLength(1), 4);
+ as.equal(ns.nsWriteLength(9), 12);
+ as.equal(ns.nsWriteLength(10), 14);
+ }
+ });
+
+ ts.runTests();
+})();
+
+(function() {
var ts = new at.TestSuite('nsPayload');
ts.addTests({
@@ -88,6 +103,18 @@ var ns = require('../lib/ns');
}
};
+ var beq = function(as, pay, payStart, payEnd, bufLen, bufOff) {
+ var buf = new Buffer(ns.nsWriteLength(bufLen));
+ var nsLen = ns.nsWrite.call(this, pay, payStart, payEnd, buf, bufOff)
+ as.ok(nsLen >= 3);
+
+ var bb = buf.slice(bufOff, bufOff + nsLen);
+ as.equal(
+ bb.toString(),
+ ns.nsWrite(pay, payStart, payEnd)
+ );
+ };
+
var ts = new at.TestSuite('nsWrite');
ts.addTests({
@@ -112,6 +139,11 @@ var ns = require('../lib/ns');
as.equal(ns.nsWrite(new Buffer('abc')), '3:abc,');
as.equal(ns.nsWrite(new Buffer('abc'), 1), '2:bc,');
as.equal(ns.nsWrite(new Buffer('abc'), 1, 2), '1:b,');
+ },
+ 'bufTarget' : function(as) {
+ beq(as, 'abc', 0, 3, 3, 0);
+ beq(as, 'abc', 0, 1, 3, 0);
+ beq(as, 'abc', 0, 3, 10, 1);
}
});

0 comments on commit f659aa5

Please sign in to comment.