Browse files

added the `reinterpretUntilZeros()` function

This is the preferred way to read beyond the length of a Buffer
i.e. when trying to find the end of a NULL-terminated string
  • Loading branch information...
1 parent 711d1f9 commit 7bc292a4e4f230e96c8c6206ccc2e5450de21b06 @TooTallNate committed May 30, 2012
Showing with 83 additions and 2 deletions.
  1. +16 −0 lib/ref.js
  2. +45 −2 src/binding.cc
  3. +22 −0 test/reinterpret.js
View
16 lib/ref.js
@@ -316,6 +316,17 @@ exports.reinterpret = function reinterpret (buffer, size) {
return rtn
}
+/**
+ */
+
+exports._reinterpretUntilZeros = exports.reinterpretUntilZeros
+exports.reinterpretUntilZeros = function reinterpretUntilZeros (buffer, size) {
+ debug('reinterpreting buffer to until %d NULL bytes are found', size)
+ var rtn = exports._reinterpretUntilZeros(buffer, size)
+ exports._attach(rtn, buffer)
+ return rtn
+}
+
/**
* Types.
@@ -595,6 +606,10 @@ Buffer.prototype.reinterpret = function reinterpret (size) {
return exports.reinterpret(this, size)
}
+Buffer.prototype.reinterpretUntilZeros = function reinterpretUntilZeros (size) {
+ return exports.reinterpretUntilZeros(this, size)
+}
+
// does SlowBuffer inherit from Buffer? (node >= v0.7.9)
if (!(exports.NULL instanceof Buffer)) {
debug('extending SlowBuffer\'s prototype since it doesn\'t inherit from Buffer.prototype')
@@ -616,6 +631,7 @@ if (!(exports.NULL instanceof Buffer)) {
SlowBuffer.prototype.readCString = Buffer.prototype.readCString
SlowBuffer.prototype.writeCString = Buffer.prototype.writeCString
SlowBuffer.prototype.reinterpret = Buffer.prototype.reinterpret
+ SlowBuffer.prototype.reinterpretUntilZeros = Buffer.prototype.reinterpretUntilZeros
SlowBuffer.prototype['readInt64' + exports.endianness] = Buffer.prototype['readInt64' + exports.endianness]
SlowBuffer.prototype['writeInt64' + exports.endianness] = Buffer.prototype['writeInt64' + exports.endianness]
SlowBuffer.prototype['readUInt64' + exports.endianness] = Buffer.prototype['readUInt64' + exports.endianness]
View
47 src/binding.cc
@@ -441,7 +441,7 @@ Handle<Value> ReadCString(const Arguments& args) {
* as the given buffer, but with the specified size.
*
* args[0] - Buffer - the "buf" Buffer instance to read the address from
- * args[1] - Number - the offset from the "buf" buffer's address to read from
+ * args[1] - Number - the size in bytes that the returned Buffer should be
*/
Handle<Value> ReinterpretBuffer(const Arguments& args) {
@@ -450,7 +450,7 @@ Handle<Value> ReinterpretBuffer(const Arguments& args) {
Local<Value> buf = args[0];
if (!Buffer::HasInstance(buf)) {
return ThrowException(Exception::TypeError(
- String::New("readCString: Buffer instance expected")));
+ String::New("reinterpret: Buffer instance expected")));
}
char *ptr = Buffer::Data(buf.As<Object>());
@@ -461,6 +461,48 @@ Handle<Value> ReinterpretBuffer(const Arguments& args) {
return scope.Close(rtn->handle_);
}
+/*
+ * Returns a new Buffer instance that has the same memory address
+ * as the given buffer, but with a length up to the first aligned set of values of
+ * 0 in a row for the given length.
+ *
+ * args[0] - Buffer - the "buf" Buffer instance to read the address from
+ * args[1] - Number - the number of sequential 0-byte values that need to be read
+ */
+
+Handle<Value> ReinterpretBufferUntilZeros(const Arguments& args) {
+ HandleScope scope;
+
+ Local<Value> buf = args[0];
+ if (!Buffer::HasInstance(buf)) {
+ return ThrowException(Exception::TypeError(
+ String::New("reinterpretUntilZeros: Buffer instance expected")));
+ }
+
+ char *ptr = Buffer::Data(buf.As<Object>());
+ uint32_t numZeros = args[1]->Uint32Value();
+ uint32_t i = 0;
+ size_t size = 0;
+ bool end = false;
+
+ while (!end && size < 10000) {
+ end = true;
+ for (i = 0; i < numZeros; i++) {
+ if (ptr[size + i] != 0) {
+ end = false;
+ break;
+ }
+ }
+ if (!end) {
+ size += numZeros;
+ }
+ }
+
+ Buffer *rtn = Buffer::New(ptr, size, read_pointer_cb, NULL);
+
+ return scope.Close(rtn->handle_);
+}
+
} // anonymous namespace
@@ -566,5 +608,6 @@ void init (Handle<Object> target) {
NODE_SET_METHOD(target, "writeUInt64", WriteUInt64);
NODE_SET_METHOD(target, "readCString", ReadCString);
NODE_SET_METHOD(target, "reinterpret", ReinterpretBuffer);
+ NODE_SET_METHOD(target, "reinterpretUntilZeros", ReinterpretBufferUntilZeros);
}
NODE_MODULE(binding, init);
View
22 test/reinterpret.js
@@ -42,4 +42,26 @@ describe('reinterpret()', function () {
assert(origGCd, '"buf" has not been garbage collected')
})
+ describe('reinterpretUntilZeros()', function () {
+
+ it('should return a new Buffer instance up until the first 0', function () {
+ var buf = new Buffer('hello\0world')
+ var buf2 = buf.reinterpretUntilZeros(1)
+ assert.equal(buf2.length, 'hello'.length)
+ assert.equal(buf2.toString(), 'hello')
+ })
+
+ it('should return a new Buffer instance up until the first 2-byte sequence of 0s', function () {
+ var str = 'hello world'
+ var buf = new Buffer(50)
+ var len = buf.write(str, 'ucs2')
+ buf.writeInt16LE(0, len) // NULL terminate the string
+
+ var buf2 = buf.reinterpretUntilZeros(2)
+ assert.equal(str.length, buf2.length / 2)
+ assert.equal(buf2.toString('ucs2'), str)
+ })
+
+ })
+
})

0 comments on commit 7bc292a

Please sign in to comment.