From 528015e0d84063891f7fbbc7d5bde3a2a38d8b0d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 23 Jul 2010 13:52:44 -0700 Subject: [PATCH] Implement buffer.toString('base64') --- lib/buffer.js | 3 ++ src/node_buffer.cc | 77 ++++++++++++++++++++++++++++++++++++++ src/node_buffer.h | 1 + test/simple/test-buffer.js | 14 +++++++ 4 files changed, 95 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index ef46482151..e58a34b67e 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -42,6 +42,9 @@ Buffer.prototype.toString = function (encoding, start, stop) { case 'binary': return this.binarySlice(start, stop); + case 'base64': + return this.base64Slice(start, stop); + default: throw new Error('Unknown encoding'); } diff --git a/src/node_buffer.cc b/src/node_buffer.cc index ce959d8498..c896b041b4 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -272,6 +272,82 @@ Handle Buffer::Utf8Slice(const Arguments &args) { return scope.Close(string); } +static char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +Handle Buffer::Base64Slice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + + int n = end - start; + int out_len = (n + 2 - ((n + 2) % 3)) / 3 * 4; + char *out = new char[out_len]; + + char bitbuf[3]; + int i = start; // data() index + int j = 0; // out index + char c; + bool b1_oob, b2_oob; + + while (i < end) { + bitbuf[0] = parent->data()[i++]; + + if (i < end) { + bitbuf[1] = parent->data()[i]; + b1_oob = false; + } else { + bitbuf[1] = 0; + b1_oob = true; + } + i++; + + if (i < end) { + bitbuf[2] = parent->data()[i]; + b2_oob = false; + } else { + bitbuf[2] = 0; + b2_oob = true; + } + i++; + + + c = bitbuf[0] >> 2; + assert(c < 64); + out[j++] = base64_table[c]; + assert(j < out_len); + + c = ((bitbuf[0] & 0x03) << 4) | (bitbuf[1] >> 4); + assert(c < 64); + out[j++] = base64_table[c]; + assert(j < out_len); + + if (b1_oob) { + out[j++] = '='; + } else { + c = ((bitbuf[1] & 0x0F) << 2) | (bitbuf[2] >> 6); + assert(c < 64); + out[j++] = base64_table[c]; + } + assert(j < out_len); + + if (b2_oob) { + out[j++] = '='; + } else { + c = bitbuf[2] & 0x3F; + assert(c < 64); + out[j++] = base64_table[c]; + } + assert(j <= out_len); + } + + Local string = String::New(out, out_len); + delete [] out; + return scope.Close(string); +} + Handle Buffer::Slice(const Arguments &args) { HandleScope scope; @@ -534,6 +610,7 @@ void Buffer::Initialize(Handle target) { // copy free NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice); NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice); NODE_SET_PROTOTYPE_METHOD(constructor_template, "slice", Buffer::Slice); // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice); // copy diff --git a/src/node_buffer.h b/src/node_buffer.h index dd9d0db51c..47dbe08180 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -54,6 +54,7 @@ class Buffer : public ObjectWrap { static v8::Handle Slice(const v8::Arguments &args); static v8::Handle BinarySlice(const v8::Arguments &args); static v8::Handle AsciiSlice(const v8::Arguments &args); + 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 AsciiWrite(const v8::Arguments &args); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 5776997112..63a025fbd5 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -229,3 +229,17 @@ assert.deepEqual(e, new Buffer([195, 188, 98, 101, 114])); var f = new Buffer('über', 'ascii'); assert.deepEqual(f, new Buffer([252, 98, 101, 114])); + + +// +// Test toString('base64') +// +assert.equal('TWFu', (new Buffer('Man')).toString('base64')); +// big example +quote = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; +expected = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="; +assert.equal(expected, (new Buffer(quote)).toString('base64')); + + + +