Browse Source

Add buffer.unpack

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
785531691b
  1. 68
      src/node_buffer.cc
  2. 1
      src/node_buffer.h
  3. 22
      test/mjsunit/test-buffer.js

68
src/node_buffer.cc

@ -4,6 +4,8 @@
#include <stdlib.h> // malloc, free
#include <v8.h>
#include <arpa/inet.h> // htons, htonl
#include <node.h>
namespace node {
@ -261,6 +263,70 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
}
// buffer.unpack(format, index);
// Starting at 'index', unpacks binary from the buffer into an array.
// 'format' is a string
//
// FORMAT RETURNS
// N uint32_t a 32bit unsigned integer in network byte order
// n uint16_t a 16bit unsigned integer in network byte order
// o uint8_t a 8bit unsigned integer
Handle<Value> Buffer::Unpack(const Arguments &args) {
HandleScope scope;
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
if (!args[0]->IsString()) {
return ThrowException(Exception::TypeError(String::New(
"Argument must be a string")));
}
String::AsciiValue format(args[0]->ToString());
int index = args[1]->IntegerValue();
#define OUT_OF_BOUNDS ThrowException(Exception::Error(String::New("Out of bounds")))
Local<Array> array = Array::New(format.length());
uint8_t uint8;
uint16_t uint16;
uint32_t uint32;
for (int i = 0; i < format.length(); i++) {
switch ((*format)[i]) {
// 32bit unsigned integer in network byte order
case 'N':
if (index + 3 >= buffer->length_) return OUT_OF_BOUNDS;
uint32 = htonl(*(uint32_t*)(buffer->data_ + index));
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint32));
index += 4;
break;
// 16bit unsigned integer in network byte order
case 'n':
if (index + 1 >= buffer->length_) return OUT_OF_BOUNDS;
uint16 = htons(*(uint16_t*)(buffer->data_ + index));
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint16));
index += 2;
break;
// a single octet, unsigned.
case 'o':
if (index >= buffer->length_) return OUT_OF_BOUNDS;
uint8 = (uint8_t)buffer->data_[index];
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint8));
index += 1;
break;
default:
return ThrowException(Exception::Error(
String::New("Unknown format character")));
}
}
return scope.Close(array);
}
// var nbytes = Buffer.utf8Length("string")
Handle<Value> Buffer::Utf8Length(const Arguments &args) {
HandleScope scope;
@ -280,6 +346,7 @@ bool Buffer::HasInstance(Handle<Value> val) {
}
void Buffer::Initialize(Handle<Object> target) {
HandleScope scope;
@ -299,6 +366,7 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack);
NODE_SET_METHOD(constructor_template->GetFunction(), "utf8Length", Buffer::Utf8Length);

1
src/node_buffer.h

@ -46,6 +46,7 @@ class Buffer : public ObjectWrap {
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Length(const v8::Arguments &args);
static v8::Handle<v8::Value> Unpack(const v8::Arguments &args);
int AsciiWrite(char *string, int offset, int length);
int Utf8Write(char *string, int offset, int length);

22
test/mjsunit/test-buffer.js

@ -50,4 +50,26 @@ for (var j = 0; j < 10000; j++) {
}
// unpack
var b = new process.Buffer(10);
b[0] = 0x00;
b[1] = 0x01;
b[2] = 0x03;
b[3] = 0x00;
assert.deepEqual([0x0001], b.unpack('n', 0));
assert.deepEqual([0x0001, 0x0300], b.unpack('nn', 0));
assert.deepEqual([0x0103], b.unpack('n', 1));
assert.deepEqual([0x0300], b.unpack('n', 2));
assert.deepEqual([0x00010300], b.unpack('N', 0));
assert.throws(function () {
b.unpack('N', 8);
});
b[4] = 0xDE;
b[5] = 0xAD;
b[6] = 0xBE;
b[7] = 0xEF;
assert.deepEqual([0xDEADBEEF], b.unpack('N', 4));

Loading…
Cancel
Save