From cf1db4f3043fce0474c421dc547b8bd2f9616354 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 18 Oct 2010 11:15:20 -0700 Subject: [PATCH] base64 decode should handle whitespace --- lib/buffer.js | 2 +- src/node_buffer.cc | 60 ++++++++++++++++++++++++++------------ test/simple/test-buffer.js | 19 ++++++++++++ 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index ecb25b7e57..e5539581d5 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -145,7 +145,7 @@ function Buffer (subject, encoding, offset) { } } else if (type == 'string') { // We are a string - this.write(subject, 0, encoding); + this.length = this.write(subject, 0, encoding); } } diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 5c4e3c1bfe..3f254081f5 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -222,15 +222,16 @@ static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; static const 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,-2,-1,-1,-2,-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 + ,-2,-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 }; +#define unbase64(x) unbase64_table[(int)(x)] Handle Buffer::Base64Slice(const Arguments &args) { @@ -436,16 +437,21 @@ Handle Buffer::AsciiWrite(const Arguments &args) { return scope.Close(Integer::New(written)); } + // var bytesWritten = buffer.base64Write(string, offset, [maxLength]); Handle Buffer::Base64Write(const Arguments &args) { HandleScope scope; - assert(unbase64_table[(int)'/'] == 63); - assert(unbase64_table[(int)'+'] == 62); - assert(unbase64_table[(int)'T'] == 19); - assert(unbase64_table[(int)'Z'] == 25); - assert(unbase64_table[(int)'t'] == 45); - assert(unbase64_table[(int)'z'] == 51); + assert(unbase64('/') == 63); + assert(unbase64('+') == 62); + assert(unbase64('T') == 19); + assert(unbase64('Z') == 25); + assert(unbase64('t') == 45); + assert(unbase64('z') == 51); + + assert(unbase64(' ') == -2); + assert(unbase64('\n') == -2); + assert(unbase64('\r') == -2); Buffer *buffer = ObjectWrap::Unwrap(args.This()); @@ -475,29 +481,47 @@ Handle Buffer::Base64Write(const Arguments &args) { } char a, b, c, d; - char* dst = buffer->data_ + offset; + char* start = buffer->data_ + offset; + char* dst = start; const char *src = *s; const char *const srcEnd = src + s.length(); while (src < srcEnd) { - const int remaining = srcEnd - src; + int remaining = srcEnd - src; + + while (unbase64(*src) < 0 && src < srcEnd) { + src++; + remaining--; + } if (remaining == 0 || *src == '=') break; - a = unbase64_table[(int)*src++]; + a = unbase64(*src++); - if (remaining == 1 || *src == '=') break; - b = unbase64_table[(int)*src++]; + while (unbase64(*src) < 0 && src < srcEnd) { + src++; + remaining--; + } + if (remaining <= 1 || *src == '=') break; + b = unbase64(*src++); *dst++ = (a << 2) | ((b & 0x30) >> 4); - if (remaining == 2 || *src == '=') break; - c = unbase64_table[(int)*src++]; + while (unbase64(*src) < 0 && src < srcEnd) { + src++; + remaining--; + } + if (remaining <= 2 || *src == '=') break; + c = unbase64(*src++); *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); - if (remaining == 3 || *src == '=') break; - d = unbase64_table[(int)*src++]; + while (unbase64(*src) < 0 && src < srcEnd) { + src++; + remaining--; + } + if (remaining <= 3 || *src == '=') break; + d = unbase64(*src++); *dst++ = ((c & 0x03) << 6) | (d & 0x3F); } - return scope.Close(Integer::New(size)); + return scope.Close(Integer::New(dst - start)); } diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 78a2106a4a..512aea5970 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -238,6 +238,25 @@ bytesWritten = b.write(expected, 0, 'base64'); assert.equal(quote.length, bytesWritten); assert.equal(quote, b.toString('ascii', 0, quote.length)); +// check that the base64 decoder ignores whitespace +var expectedWhite = expected.slice(0, 60) + " \n" + + expected.slice(60, 120) + " \n" + + expected.slice(120, 180) + " \n" + + expected.slice(180, 240) + " \n" + + expected.slice(240, 300) + "\n" + + expected.slice(300, 360) + "\n"; +b = new Buffer(1024); +bytesWritten = b.write(expectedWhite, 0, 'base64'); +assert.equal(quote.length, bytesWritten); +assert.equal(quote, b.toString('ascii', 0, quote.length)); + +// check that the base64 decoder on the constructor works +// even in the presence of whitespace. +b = new Buffer(expectedWhite, 'base64'); +assert.equal(quote.length, b.length); +assert.equal(quote, b.toString('ascii', 0, quote.length)); + + assert.equal(new Buffer('', 'base64').toString(), ''); assert.equal(new Buffer('K', 'base64').toString(), '');