Browse Source

Implement buffer.write for base64

There might be an off-by-one on the returned value.
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
2c1ca4078d
  1. 3
      lib/buffer.js
  2. 96
      src/node_buffer.cc
  3. 1
      src/node_buffer.h
  4. 5
      test/simple/test-buffer.js

3
lib/buffer.js

@ -77,6 +77,9 @@ Buffer.prototype.write = function (string) {
case 'binary': case 'binary':
return this.binaryWrite(string, offset); return this.binaryWrite(string, offset);
case 'base64':
return this.base64Write(string, offset);
default: default:
throw new Error('Unknown encoding'); throw new Error('Unknown encoding');
} }

96
src/node_buffer.cc

@ -275,6 +275,16 @@ Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
static char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" static char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; "0123456789+/";
static int unbase64_table[] =
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63
,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1
,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14
,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1
,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1
};
Handle<Value> Buffer::Base64Slice(const Arguments &args) { Handle<Value> Buffer::Base64Slice(const Arguments &args) {
@ -485,6 +495,91 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
} }
// var bytesWritten = buffer.base64Write(string, offset);
Handle<Value> Buffer::Base64Write(const Arguments &args) {
HandleScope scope;
assert(unbase64_table['/'] == 63);
assert(unbase64_table['+'] == 62);
assert(unbase64_table['T'] == 19);
assert(unbase64_table['Z'] == 25);
assert(unbase64_table['t'] == 45);
assert(unbase64_table['z'] == 51);
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
if (!args[0]->IsString()) {
return ThrowException(Exception::TypeError(String::New(
"Argument must be a string")));
}
String::AsciiValue s(args[0]->ToString());
size_t offset = args[1]->Int32Value();
if (offset >= buffer->length_) {
return ThrowException(Exception::TypeError(String::New(
"Offset is out of bounds")));
}
char *input = *s;
int input_len = s.length();
char *start = buffer->data() + offset;
char *p = start;
const char *pe = buffer->data() + buffer->length_;
int i = 0;
char a,b,c,d;
bool b_oob, c_oob;
while (i < input_len && p < pe) {
if (input[i] == '=' || i >= input_len) break;
a = unbase64_table[input[i]];
i++;
if (input[i] == '=' || i >= input_len) {
b = 0;
b_oob = true;
} else {
b = unbase64_table[input[i]];
b_oob = false;
}
i++;
if (b_oob || input[i] == '=' || i >= input_len) {
c = 0;
c_oob = true;
} else {
c = unbase64_table[input[i]];
c_oob = false;
}
i++;
if (c_oob || input[i] == '=' || i >= input_len) {
d = 0;
} else {
d = unbase64_table[input[i]];
}
i++;
*p = (a << 2) | ((b & 0x30) >> 4);
if (++p >= pe) break;
if (b_oob) break;
*p = ((b & 0x0F) << 4) | ((c & 0x3c) >> 2);
if (++p >= pe) break;
if (c_oob) break;
*p = ((c & 0x03) << 6) | (d & 0x3f);
if (++p >= pe) break;
}
return scope.Close(Integer::New(p - start));
}
Handle<Value> Buffer::BinaryWrite(const Arguments &args) { Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
HandleScope scope; HandleScope scope;
@ -619,6 +714,7 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write); NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite); NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite); NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack); NODE_SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy); NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);

1
src/node_buffer.h

@ -57,6 +57,7 @@ class Buffer : public ObjectWrap {
static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args); static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args); static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args); static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Base64Write(const v8::Arguments &args);
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args); 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> Utf8Write(const v8::Arguments &args);
static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args); static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);

5
test/simple/test-buffer.js

@ -241,5 +241,10 @@ expected = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBi
assert.equal(expected, (new Buffer(quote)).toString('base64')); assert.equal(expected, (new Buffer(quote)).toString('base64'));
b = new Buffer(1024);
bytesWritten = b.write(expected, 0, 'base64');
assert.equal(quote, b.toString('ascii', 0, quote.length));
assert.equal(quote.length+1, bytesWritten); // writes a \0 too

Loading…
Cancel
Save