diff --git a/benchmark/buffer-base64-encode.js b/benchmark/buffer-base64-encode.js new file mode 100644 index 0000000000..7ead3a575d --- /dev/null +++ b/benchmark/buffer-base64-encode.js @@ -0,0 +1,27 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var N = 64*1024*1024 +var b = Buffer(N); +var s = ''; +for (var i = 0; i < 256; ++i) s += String.fromCharCode(i); +for (var i = 0; i < N; i += 256) b.write(s, i, 256, 'ascii'); +for (var i = 0; i < 32; ++i) b.toString('base64'); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index a49e8b5e6a..14ddb2f6a9 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -276,9 +276,6 @@ Handle Buffer::Ucs2Slice(const Arguments &args) { return scope.Close(string); } -static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; // supports regular and URL-safe base64 static const int unbase64_table[] = @@ -307,69 +304,65 @@ Handle Buffer::Base64Slice(const Arguments &args) { 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]; - - uint8_t 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++; + unsigned slen = end - start; + const char* src = parent->data_ + start; + unsigned dlen = (slen + 2 - ((slen + 2) % 3)) / 3 * 4; + char* dst = new char[dlen]; - c = bitbuf[0] >> 2; - assert(c < 64); - out[j++] = base64_table[(int)c]; - assert(j < out_len); + unsigned a; + unsigned b; + unsigned c; + unsigned i; + unsigned k; + unsigned n; - c = ((bitbuf[0] & 0x03) << 4) | (bitbuf[1] >> 4); - assert(c < 64); - out[j++] = base64_table[(int)c]; - assert(j < out_len); + static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; - if (b1_oob) { - out[j++] = '='; - } else { - c = ((bitbuf[1] & 0x0F) << 2) | (bitbuf[2] >> 6); - assert(c < 64); - out[j++] = base64_table[(int)c]; - } - assert(j < out_len); + i = 0; + k = 0; + n = slen / 3 * 3; - if (b2_oob) { - out[j++] = '='; - } else { - c = bitbuf[2] & 0x3F; - assert(c < 64); - out[j++] = base64_table[(int)c]; + while (i < n) { + a = src[i + 0] & 0xff; + b = src[i + 1] & 0xff; + c = src[i + 2] & 0xff; + + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; + dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)]; + dst[k + 3] = table[c & 0x3f]; + + i += 3; + k += 4; + } + + if (n != slen) { + switch (slen - n) { + case 1: + a = src[i + 0] & 0xff; + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[(a & 3) << 4]; + dst[k + 2] = '='; + dst[k + 3] = '='; + break; + + case 2: + a = src[i + 0] & 0xff; + b = src[i + 1] & 0xff; + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; + dst[k + 2] = table[(b & 0x0f) << 2]; + dst[k + 3] = '='; + break; } - assert(j <= out_len); } - Local string = String::New(out, out_len); - delete [] out; + Local string = String::New(dst, dlen); + delete [] dst; + return scope.Close(string); }