Browse Source

Buffer: adjust buffer size so the base64-decoded input fits snugly.

Stops Valgrind from complaining about uninitialized memory access.
v0.7.4-release
Ben Noordhuis 15 years ago
committed by Ryan Dahl
parent
commit
95638c9b0d
  1. 2
      src/node.cc
  2. 2
      src/node.h
  3. 28
      src/node_buffer.cc
  4. 42
      test/simple/test-buffer.js

2
src/node.cc

@ -783,6 +783,8 @@ enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
return UTF8;
} else if (strcasecmp(*encoding, "ascii") == 0) {
return ASCII;
} else if (strcasecmp(*encoding, "base64") == 0) {
return BASE64;
} else if (strcasecmp(*encoding, "binary") == 0) {
return BINARY;
} else if (strcasecmp(*encoding, "raw") == 0) {

2
src/node.h

@ -41,7 +41,7 @@ do { \
__callback##_TEM); \
} while (0)
enum encoding {ASCII, UTF8, BINARY};
enum encoding {ASCII, UTF8, BASE64, BINARY};
enum encoding ParseEncoding(v8::Handle<v8::Value> encoding_v,
enum encoding _default = BINARY);
void FatalException(v8::TryCatch &try_catch);

28
src/node_buffer.cc

@ -149,6 +149,29 @@ Handle<Value> Buffer::New(const Arguments &args) {
Local<String> s = args[0]->ToString();
enum encoding e = ParseEncoding(args[1], UTF8);
int length = e == UTF8 ? s->Utf8Length() : s->Length();
// input gets base64-decoded, adjust buffer size
if (e == BASE64 && length > 0) {
const int remainder = length % 4;
length = (length / 4) * 3;
if (remainder) {
if (length == 0 && remainder == 1) {
// special case: 1-byte input cannot be decoded, return empty buffer
length = 0;
} else {
// non-padded input, add 1 or 2 extra bytes
length += 1 + (remainder == 3);
}
} else {
// check for trailing padding (1 or 2 bytes)
const String::AsciiValue data(s);
const char *const end = *data + data.length();
if (end[-1] == '=') length--;
if (end[-2] == '=') length--;
}
}
buffer = new Buffer(length);
} else if (Buffer::HasInstance(args[0]) && args.Length() > 2) {
// var slice = new Buffer(buffer, 123, 130);
@ -516,6 +539,11 @@ Handle<Value> Buffer::Base64Write(const Arguments &args) {
String::AsciiValue s(args[0]->ToString());
size_t offset = args[1]->Int32Value();
// handle zero-length buffers graciously
if (offset == 0 && buffer->length_ == 0) {
return scope.Close(Integer::New(0));
}
if (offset >= buffer->length_) {
return ThrowException(Exception::TypeError(String::New(
"Offset is out of bounds")));

42
test/simple/test-buffer.js

@ -258,5 +258,43 @@ 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
assert.equal(new Buffer('', 'base64').toString(), '');
assert.equal(new Buffer('K', 'base64').toString(), '');
// multiple-of-4 with padding
assert.equal(new Buffer('Kg==', 'base64').toString(), '*');
assert.equal(new Buffer('Kio=', 'base64').toString(), '**');
assert.equal(new Buffer('Kioq', 'base64').toString(), '***');
assert.equal(new Buffer('KioqKg==', 'base64').toString(), '****');
assert.equal(new Buffer('KioqKio=', 'base64').toString(), '*****');
assert.equal(new Buffer('KioqKioq', 'base64').toString(), '******');
assert.equal(new Buffer('KioqKioqKg==', 'base64').toString(), '*******');
assert.equal(new Buffer('KioqKioqKio=', 'base64').toString(), '********');
assert.equal(new Buffer('KioqKioqKioq', 'base64').toString(), '*********');
assert.equal(new Buffer('KioqKioqKioqKg==', 'base64').toString(), '**********');
assert.equal(new Buffer('KioqKioqKioqKio=', 'base64').toString(), '***********');
assert.equal(new Buffer('KioqKioqKioqKioq', 'base64').toString(), '************');
assert.equal(new Buffer('KioqKioqKioqKioqKg==', 'base64').toString(), '*************');
assert.equal(new Buffer('KioqKioqKioqKioqKio=', 'base64').toString(), '**************');
assert.equal(new Buffer('KioqKioqKioqKioqKioq', 'base64').toString(), '***************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKg==', 'base64').toString(), '****************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKio=', 'base64').toString(), '*****************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKioq', 'base64').toString(), '******************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKg==', 'base64').toString(), '*******************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKio=', 'base64').toString(), '********************');
// no padding, not a multiple of 4
assert.equal(new Buffer('Kg', 'base64').toString(), '*');
assert.equal(new Buffer('Kio', 'base64').toString(), '**');
assert.equal(new Buffer('KioqKg', 'base64').toString(), '****');
assert.equal(new Buffer('KioqKio', 'base64').toString(), '*****');
assert.equal(new Buffer('KioqKioqKg', 'base64').toString(), '*******');
assert.equal(new Buffer('KioqKioqKio', 'base64').toString(), '********');
assert.equal(new Buffer('KioqKioqKioqKg', 'base64').toString(), '**********');
assert.equal(new Buffer('KioqKioqKioqKio', 'base64').toString(), '***********');
assert.equal(new Buffer('KioqKioqKioqKioqKg', 'base64').toString(), '*************');
assert.equal(new Buffer('KioqKioqKioqKioqKio', 'base64').toString(), '**************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKg', 'base64').toString(), '****************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKio', 'base64').toString(), '*****************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKg', 'base64').toString(), '*******************');
assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKio', 'base64').toString(), '********************');

Loading…
Cancel
Save