Skip to content

Commit 7855316

Browse files
committed
Add buffer.unpack
1 parent 49451c1 commit 7855316

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

src/node_buffer.cc

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <stdlib.h> // malloc, free
55
#include <v8.h>
66

7+
#include <arpa/inet.h> // htons, htonl
8+
79
#include <node.h>
810

911
namespace node {
@@ -261,6 +263,70 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
261263
}
262264

263265

266+
// buffer.unpack(format, index);
267+
// Starting at 'index', unpacks binary from the buffer into an array.
268+
// 'format' is a string
269+
//
270+
// FORMAT RETURNS
271+
// N uint32_t a 32bit unsigned integer in network byte order
272+
// n uint16_t a 16bit unsigned integer in network byte order
273+
// o uint8_t a 8bit unsigned integer
274+
Handle<Value> Buffer::Unpack(const Arguments &args) {
275+
HandleScope scope;
276+
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
277+
278+
if (!args[0]->IsString()) {
279+
return ThrowException(Exception::TypeError(String::New(
280+
"Argument must be a string")));
281+
}
282+
283+
String::AsciiValue format(args[0]->ToString());
284+
int index = args[1]->IntegerValue();
285+
286+
#define OUT_OF_BOUNDS ThrowException(Exception::Error(String::New("Out of bounds")))
287+
288+
Local<Array> array = Array::New(format.length());
289+
290+
uint8_t uint8;
291+
uint16_t uint16;
292+
uint32_t uint32;
293+
294+
for (int i = 0; i < format.length(); i++) {
295+
switch ((*format)[i]) {
296+
// 32bit unsigned integer in network byte order
297+
case 'N':
298+
if (index + 3 >= buffer->length_) return OUT_OF_BOUNDS;
299+
uint32 = htonl(*(uint32_t*)(buffer->data_ + index));
300+
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint32));
301+
index += 4;
302+
break;
303+
304+
// 16bit unsigned integer in network byte order
305+
case 'n':
306+
if (index + 1 >= buffer->length_) return OUT_OF_BOUNDS;
307+
uint16 = htons(*(uint16_t*)(buffer->data_ + index));
308+
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint16));
309+
index += 2;
310+
break;
311+
312+
// a single octet, unsigned.
313+
case 'o':
314+
if (index >= buffer->length_) return OUT_OF_BOUNDS;
315+
uint8 = (uint8_t)buffer->data_[index];
316+
array->Set(Integer::New(i), Integer::NewFromUnsigned(uint8));
317+
index += 1;
318+
break;
319+
320+
default:
321+
return ThrowException(Exception::Error(
322+
String::New("Unknown format character")));
323+
}
324+
}
325+
326+
return scope.Close(array);
327+
}
328+
329+
264330
// var nbytes = Buffer.utf8Length("string")
265331
Handle<Value> Buffer::Utf8Length(const Arguments &args) {
266332
HandleScope scope;
@@ -280,6 +346,7 @@ bool Buffer::HasInstance(Handle<Value> val) {
280346
}
281347

282348

349+
283350
void Buffer::Initialize(Handle<Object> target) {
284351
HandleScope scope;
285352

@@ -299,6 +366,7 @@ void Buffer::Initialize(Handle<Object> target) {
299366

300367
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
301368
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
369+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack);
302370

303371
NODE_SET_METHOD(constructor_template->GetFunction(), "utf8Length", Buffer::Utf8Length);
304372

src/node_buffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Buffer : public ObjectWrap {
4646
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
4747
static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
4848
static v8::Handle<v8::Value> Utf8Length(const v8::Arguments &args);
49+
static v8::Handle<v8::Value> Unpack(const v8::Arguments &args);
4950

5051
int AsciiWrite(char *string, int offset, int length);
5152
int Utf8Write(char *string, int offset, int length);

test/mjsunit/test-buffer.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,26 @@ for (var j = 0; j < 10000; j++) {
5050
}
5151

5252

53+
// unpack
5354

55+
var b = new process.Buffer(10);
56+
b[0] = 0x00;
57+
b[1] = 0x01;
58+
b[2] = 0x03;
59+
b[3] = 0x00;
60+
61+
assert.deepEqual([0x0001], b.unpack('n', 0));
62+
assert.deepEqual([0x0001, 0x0300], b.unpack('nn', 0));
63+
assert.deepEqual([0x0103], b.unpack('n', 1));
64+
assert.deepEqual([0x0300], b.unpack('n', 2));
65+
assert.deepEqual([0x00010300], b.unpack('N', 0));
66+
assert.throws(function () {
67+
b.unpack('N', 8);
68+
});
69+
70+
b[4] = 0xDE;
71+
b[5] = 0xAD;
72+
b[6] = 0xBE;
73+
b[7] = 0xEF;
74+
75+
assert.deepEqual([0xDEADBEEF], b.unpack('N', 4));

0 commit comments

Comments
 (0)