Browse Source

base64 decode should handle whitespace

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
cf1db4f304
  1. 2
      lib/buffer.js
  2. 60
      src/node_buffer.cc
  3. 19
      test/simple/test-buffer.js

2
lib/buffer.js

@ -145,7 +145,7 @@ function Buffer (subject, encoding, offset) {
} }
} else if (type == 'string') { } else if (type == 'string') {
// We are a string // We are a string
this.write(subject, 0, encoding); this.length = this.write(subject, 0, encoding);
} }
} }

60
src/node_buffer.cc

@ -222,15 +222,16 @@ static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; "0123456789+/";
static const int unbase64_table[] = 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,-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 ,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 ,-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 ,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 ,-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 ,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1
}; };
#define unbase64(x) unbase64_table[(int)(x)]
Handle<Value> Buffer::Base64Slice(const Arguments &args) { Handle<Value> Buffer::Base64Slice(const Arguments &args) {
@ -436,16 +437,21 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
return scope.Close(Integer::New(written)); return scope.Close(Integer::New(written));
} }
// var bytesWritten = buffer.base64Write(string, offset, [maxLength]); // var bytesWritten = buffer.base64Write(string, offset, [maxLength]);
Handle<Value> Buffer::Base64Write(const Arguments &args) { Handle<Value> Buffer::Base64Write(const Arguments &args) {
HandleScope scope; HandleScope scope;
assert(unbase64_table[(int)'/'] == 63); assert(unbase64('/') == 63);
assert(unbase64_table[(int)'+'] == 62); assert(unbase64('+') == 62);
assert(unbase64_table[(int)'T'] == 19); assert(unbase64('T') == 19);
assert(unbase64_table[(int)'Z'] == 25); assert(unbase64('Z') == 25);
assert(unbase64_table[(int)'t'] == 45); assert(unbase64('t') == 45);
assert(unbase64_table[(int)'z'] == 51); assert(unbase64('z') == 51);
assert(unbase64(' ') == -2);
assert(unbase64('\n') == -2);
assert(unbase64('\r') == -2);
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This()); Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
@ -475,29 +481,47 @@ Handle<Value> Buffer::Base64Write(const Arguments &args) {
} }
char a, b, c, d; char a, b, c, d;
char* dst = buffer->data_ + offset; char* start = buffer->data_ + offset;
char* dst = start;
const char *src = *s; const char *src = *s;
const char *const srcEnd = src + s.length(); const char *const srcEnd = src + s.length();
while (src < srcEnd) { 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; if (remaining == 0 || *src == '=') break;
a = unbase64_table[(int)*src++]; a = unbase64(*src++);
if (remaining == 1 || *src == '=') break; while (unbase64(*src) < 0 && src < srcEnd) {
b = unbase64_table[(int)*src++]; src++;
remaining--;
}
if (remaining <= 1 || *src == '=') break;
b = unbase64(*src++);
*dst++ = (a << 2) | ((b & 0x30) >> 4); *dst++ = (a << 2) | ((b & 0x30) >> 4);
if (remaining == 2 || *src == '=') break; while (unbase64(*src) < 0 && src < srcEnd) {
c = unbase64_table[(int)*src++]; src++;
remaining--;
}
if (remaining <= 2 || *src == '=') break;
c = unbase64(*src++);
*dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
if (remaining == 3 || *src == '=') break; while (unbase64(*src) < 0 && src < srcEnd) {
d = unbase64_table[(int)*src++]; src++;
remaining--;
}
if (remaining <= 3 || *src == '=') break;
d = unbase64(*src++);
*dst++ = ((c & 0x03) << 6) | (d & 0x3F); *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
} }
return scope.Close(Integer::New(size)); return scope.Close(Integer::New(dst - start));
} }

19
test/simple/test-buffer.js

@ -238,6 +238,25 @@ bytesWritten = b.write(expected, 0, 'base64');
assert.equal(quote.length, bytesWritten); assert.equal(quote.length, bytesWritten);
assert.equal(quote, b.toString('ascii', 0, quote.length)); 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('', 'base64').toString(), '');
assert.equal(new Buffer('K', 'base64').toString(), ''); assert.equal(new Buffer('K', 'base64').toString(), '');

Loading…
Cancel
Save