diff --git a/lib/buffer.js b/lib/buffer.js index e58a34b67e0..78b59051a8e 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -77,6 +77,9 @@ Buffer.prototype.write = function (string) { case 'binary': return this.binaryWrite(string, offset); + case 'base64': + return this.base64Write(string, offset); + default: throw new Error('Unknown encoding'); } diff --git a/src/node_buffer.cc b/src/node_buffer.cc index c896b041b4b..efd01b71655 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -275,6 +275,16 @@ Handle Buffer::Utf8Slice(const Arguments &args) { static char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "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 Buffer::Base64Slice(const Arguments &args) { @@ -485,6 +495,91 @@ Handle Buffer::AsciiWrite(const Arguments &args) { } +// var bytesWritten = buffer.base64Write(string, offset); +Handle 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(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 Buffer::BinaryWrite(const Arguments &args) { HandleScope scope; @@ -619,6 +714,7 @@ void Buffer::Initialize(Handle 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, "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, "copy", Buffer::Copy); diff --git a/src/node_buffer.h b/src/node_buffer.h index 47dbe081801..61fecadaf27 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -57,6 +57,7 @@ class Buffer : public ObjectWrap { static v8::Handle Base64Slice(const v8::Arguments &args); static v8::Handle Utf8Slice(const v8::Arguments &args); static v8::Handle BinaryWrite(const v8::Arguments &args); + static v8::Handle Base64Write(const v8::Arguments &args); static v8::Handle AsciiWrite(const v8::Arguments &args); static v8::Handle Utf8Write(const v8::Arguments &args); static v8::Handle ByteLength(const v8::Arguments &args); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 63a025fbd5a..0a7ed9ffaa7 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -241,5 +241,10 @@ expected = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBi 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 +