summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2013-05-02 10:44:45 -0700
committerisaacs <i@izs.me>2013-05-14 13:51:42 -0700
commit119354f7356de47cb36b5a1cebf9423e89c7f10b (patch)
tree3de84986ccfccf9c3b949685d3bfdb3e11f904ab /src
parent4e8cddddcbb7af0d7dcb39dabce6b48cef8c9957 (diff)
downloadnode-119354f7356de47cb36b5a1cebf9423e89c7f10b.tar.gz
buffer: DRY string encoding using StringBytes
This also templatizes the Buffer::*Slice functions, and the template function probably cannot be safely used outside of Node. However, it also SHOULD not be used outside of Node, so this is arguably a feature as well as a caveat.
Diffstat (limited to 'src')
-rw-r--r--src/node_buffer.cc613
-rw-r--r--src/node_buffer.h6
2 files changed, 69 insertions, 550 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 21960f885..2dfddc764 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -20,9 +20,11 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#include "node.h"
#include "node_buffer.h"
+#include "node.h"
+#include "string_bytes.h"
+
#include "v8.h"
#include "v8-profiler.h"
@@ -66,49 +68,6 @@ static Persistent<Function> fast_buffer_constructor;
Persistent<FunctionTemplate> Buffer::constructor_template;
-static inline size_t base64_decoded_size(const char *src, size_t size) {
- const char *const end = src + size;
- const int remainder = size % 4;
-
- size = (size / 4) * 3;
- if (remainder) {
- if (size == 0 && remainder == 1) {
- // special case: 1-byte input cannot be decoded
- size = 0;
- } else {
- // non-padded input, add 1 or 2 extra bytes
- size += 1 + (remainder == 3);
- }
- }
-
- // check for trailing padding (1 or 2 bytes)
- if (size > 0) {
- if (end[-1] == '=') size--;
- if (end[-2] == '=') size--;
- }
-
- return size;
-}
-
-
-static size_t ByteLength (Handle<String> string, enum encoding enc) {
- HandleScope scope;
-
- if (enc == UTF8) {
- return string->Utf8Length();
- } else if (enc == BASE64) {
- String::Utf8Value v(string);
- return base64_decoded_size(*v, v.length());
- } else if (enc == UCS2) {
- return string->Length() * 2;
- } else if (enc == HEX) {
- return string->Length() / 2;
- } else {
- return string->Length();
- }
-}
-
-
Handle<Object> Buffer::New(Handle<String> string) {
HandleScope scope;
@@ -163,7 +122,7 @@ Buffer* Buffer::New(char *data, size_t length,
}
-Handle<Value> Buffer::New(const Arguments &args) {
+Handle<Value> Buffer::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}
@@ -233,275 +192,52 @@ void Buffer::Replace(char *data, size_t length,
handle_->Set(length_symbol, Integer::NewFromUnsigned(length_));
}
-
-Handle<Value> Buffer::BinarySlice(const Arguments &args) {
+template <encoding encoding>
+Handle<Value> Buffer::StringSlice(const Arguments& args) {
HandleScope scope;
Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
SLICE_ARGS(args[0], args[1])
- char *data = parent->data_ + start;
- //Local<String> string = String::New(data, end - start);
-
- Local<Value> b = Encode(data, end - start, BINARY);
-
- return scope.Close(b);
-}
-
-
-static bool contains_non_ascii_slow(const char* buf, size_t len) {
- for (size_t i = 0; i < len; ++i) {
- if (buf[i] & 0x80) return true;
- }
- return false;
-}
-
-
-static bool contains_non_ascii(const char* src, size_t len) {
- if (len < 16) {
- return contains_non_ascii_slow(src, len);
- }
-
- const unsigned bytes_per_word = BITS_PER_LONG / CHAR_BIT;
- const unsigned align_mask = bytes_per_word - 1;
- const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
-
- if (unaligned > 0) {
- const unsigned n = bytes_per_word - unaligned;
- if (contains_non_ascii_slow(src, n)) return true;
- src += n;
- len -= n;
- }
-
-#if BITS_PER_LONG == 64
- typedef uint64_t word;
- const uint64_t mask = 0x8080808080808080ll;
-#else
- typedef uint32_t word;
- const uint32_t mask = 0x80808080l;
-#endif
-
- const word* srcw = reinterpret_cast<const word*>(src);
-
- for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
- if (srcw[i] & mask) return true;
- }
-
- const unsigned remainder = len & align_mask;
- if (remainder > 0) {
- const size_t offset = len - remainder;
- if (contains_non_ascii_slow(src + offset, remainder)) return true;
- }
-
- return false;
+ const char* src = parent->data_ + start;
+ size_t slen = (end - start);
+ return scope.Close(StringBytes::Encode(src, slen, encoding));
}
-static void force_ascii_slow(const char* src, char* dst, size_t len) {
- for (size_t i = 0; i < len; ++i) {
- dst[i] = src[i] & 0x7f;
- }
+Handle<Value> Buffer::BinarySlice(const Arguments& args) {
+ return Buffer::StringSlice<BINARY>(args);
}
-static void force_ascii(const char* src, char* dst, size_t len) {
- if (len < 16) {
- force_ascii_slow(src, dst, len);
- return;
- }
-
- const unsigned bytes_per_word = BITS_PER_LONG / CHAR_BIT;
- const unsigned align_mask = bytes_per_word - 1;
- const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
- const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
-
- if (src_unalign > 0) {
- if (src_unalign == dst_unalign) {
- const unsigned unalign = bytes_per_word - src_unalign;
- force_ascii_slow(src, dst, unalign);
- src += unalign;
- dst += unalign;
- len -= src_unalign;
- } else {
- force_ascii_slow(src, dst, len);
- return;
- }
- }
-
-#if BITS_PER_LONG == 64
- typedef uint64_t word;
- const uint64_t mask = ~0x8080808080808080ll;
-#else
- typedef uint32_t word;
- const uint32_t mask = ~0x80808080l;
-#endif
-
- const word* srcw = reinterpret_cast<const word*>(src);
- word* dstw = reinterpret_cast<word*>(dst);
-
- for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
- dstw[i] = srcw[i] & mask;
- }
-
- const unsigned remainder = len & align_mask;
- if (remainder > 0) {
- const size_t offset = len - remainder;
- force_ascii_slow(src + offset, dst + offset, remainder);
- }
+Handle<Value> Buffer::AsciiSlice(const Arguments& args) {
+ return Buffer::StringSlice<ASCII>(args);
}
-Handle<Value> Buffer::AsciiSlice(const Arguments &args) {
- HandleScope scope;
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
-
- char* data = parent->data_ + start;
- size_t len = end - start;
-
- if (contains_non_ascii(data, len)) {
- char* out = new char[len];
- force_ascii(data, out, len);
- Local<String> rc = String::New(out, len);
- delete[] out;
- return scope.Close(rc);
- }
-
- return scope.Close(String::New(data, len));
+Handle<Value> Buffer::Utf8Slice(const Arguments& args) {
+ return Buffer::StringSlice<UTF8>(args);
}
-Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
- HandleScope scope;
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
- char *data = parent->data_ + start;
- Local<String> string = String::New(data, end - start);
- return scope.Close(string);
+Handle<Value> Buffer::Ucs2Slice(const Arguments& args) {
+ return Buffer::StringSlice<UCS2>(args);
}
-Handle<Value> Buffer::Ucs2Slice(const Arguments &args) {
- HandleScope scope;
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
- uint16_t *data = (uint16_t*)(parent->data_ + start);
- Local<String> string = String::New(data, (end - start) / 2);
- return scope.Close(string);
-}
-
-Handle<Value> Buffer::HexSlice(const Arguments &args) {
- HandleScope scope;
- Buffer* parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
- char* src = parent->data_ + start;
- uint32_t dstlen = (end - start) * 2;
- if (dstlen == 0) return scope.Close(String::Empty());
- char* dst = new char[dstlen];
- for (uint32_t i = 0, k = 0; k < dstlen; i += 1, k += 2) {
- static const char hex[] = "0123456789abcdef";
- uint8_t val = static_cast<uint8_t>(src[i]);
- dst[k + 0] = hex[val >> 4];
- dst[k + 1] = hex[val & 15];
- }
- Local<String> string = String::New(dst, dstlen);
- delete[] dst;
- return scope.Close(string);
+Handle<Value> Buffer::HexSlice(const Arguments& args) {
+ return Buffer::StringSlice<HEX>(args);
}
-// supports regular and URL-safe base64
-static const int unbase64_table[] =
- {-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
- ,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,62,-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,63
- ,-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
- ,-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,-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,-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
- };
-#define unbase64(x) unbase64_table[(uint8_t)(x)]
-
-
-Handle<Value> Buffer::Base64Slice(const Arguments &args) {
- HandleScope scope;
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
-
- unsigned slen = end - start;
- const char* src = parent->data_ + start;
-
- unsigned dlen = (slen + 2 - ((slen + 2) % 3)) / 3 * 4;
- char* dst = new char[dlen];
-
- unsigned a;
- unsigned b;
- unsigned c;
- unsigned i;
- unsigned k;
- unsigned n;
-
- static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
- i = 0;
- k = 0;
- n = slen / 3 * 3;
-
- 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;
- }
- }
-
- Local<String> string = String::New(dst, dlen);
- delete [] dst;
- return scope.Close(string);
+Handle<Value> Buffer::Base64Slice(const Arguments& args) {
+ return Buffer::StringSlice<BASE64>(args);
}
// buffer.fill(value, start, end);
-Handle<Value> Buffer::Fill(const Arguments &args) {
+Handle<Value> Buffer::Fill(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsInt32()) {
@@ -522,7 +258,7 @@ Handle<Value> Buffer::Fill(const Arguments &args) {
// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
-Handle<Value> Buffer::Copy(const Arguments &args) {
+Handle<Value> Buffer::Copy(const Arguments& args) {
HandleScope scope;
Buffer *source = ObjectWrap::Unwrap<Buffer>(args.This());
@@ -573,288 +309,78 @@ Handle<Value> Buffer::Copy(const Arguments &args) {
}
-// var charsWritten = buffer.utf8Write(string, offset, [maxLength]);
-Handle<Value> Buffer::Utf8Write(const Arguments &args) {
- HandleScope scope;
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (!args[0]->IsString()) {
- return ThrowException(Exception::TypeError(String::New(
- "Argument must be a string")));
- }
-
- Local<String> s = args[0]->ToString();
-
- size_t offset = args[1]->Uint32Value();
-
- int length = s->Length();
-
- if (length == 0) {
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(0));
- return scope.Close(Integer::New(0));
- }
-
- if (length > 0 && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(buffer->length_ - offset, max_length);
-
- char* p = buffer->data_ + offset;
-
- int char_written;
-
- int written = s->WriteUtf8(p,
- max_length,
- &char_written,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(char_written));
-
- return scope.Close(Integer::New(written));
+Handle<Value> Buffer::Base64Write(const Arguments& args) {
+ return Buffer::StringWrite<BASE64>(args);
}
-
-// var charsWritten = buffer.ucs2Write(string, offset, [maxLength]);
-Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
- HandleScope scope;
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
- }
-
- Local<String> s = args[0]->ToString();
-
- size_t offset = args[1]->Uint32Value();
-
- if (s->Length() > 0 && offset >= buffer->length_) {
- return ThrowException(Exception::TypeError(String::New(
- "Offset is out of bounds")));
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(buffer->length_ - offset, max_length) / 2;
-
- uint16_t* p = (uint16_t*)(buffer->data_ + offset);
-
- int written = s->Write(p,
- 0,
- max_length,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(written));
-
- return scope.Close(Integer::New(written * 2));
+Handle<Value> Buffer::BinaryWrite(const Arguments& args) {
+ return Buffer::StringWrite<BINARY>(args);
}
-
-inline unsigned hex2bin(char c) {
- if (c >= '0' && c <= '9') return c - '0';
- if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
- if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
- return static_cast<unsigned>(-1);
+Handle<Value> Buffer::Utf8Write(const Arguments& args) {
+ return Buffer::StringWrite<UTF8>(args);
}
+Handle<Value> Buffer::Ucs2Write(const Arguments& args) {
+ return Buffer::StringWrite<UCS2>(args);
+}
Handle<Value> Buffer::HexWrite(const Arguments& args) {
- HandleScope scope;
- Buffer* parent = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (args[0]->IsString() == false) {
- return ThrowTypeError("Argument must be a string");
- }
-
- Local<String> s = args[0].As<String>();
-
- if (s->Length() % 2 != 0) {
- return ThrowTypeError("Invalid hex string");
- }
-
- uint32_t start = args[1]->Uint32Value();
- uint32_t size = args[2]->Uint32Value();
- uint32_t end = start + size;
-
- if (start >= parent->length_) {
- Local<Integer> val = Integer::New(0);
- constructor_template->GetFunction()->Set(chars_written_sym, val);
- return scope.Close(val);
- }
-
- if (end < start || end > parent->length_) { // Overflow + bounds check.
- end = parent->length_;
- size = parent->length_ - start;
- }
-
- if (size == 0) {
- Local<Integer> val = Integer::New(0);
- constructor_template->GetFunction()->Set(chars_written_sym, val);
- return scope.Close(val);
- }
-
- char* dst = parent->data_ + start;
- String::AsciiValue string(s);
- const char* src = *string;
- uint32_t max = string.length() / 2;
-
- if (max > size) {
- max = size;
- }
-
- for (uint32_t i = 0; i < max; ++i) {
- unsigned a = hex2bin(src[i * 2 + 0]);
- unsigned b = hex2bin(src[i * 2 + 1]);
- if (!~a || !~b) return ThrowTypeError("Invalid hex string");
- dst[i] = a * 16 + b;
- }
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(max * 2));
-
- return scope.Close(Integer::New(max));
+ return Buffer::StringWrite<HEX>(args);
}
+Handle<Value> Buffer::AsciiWrite(const Arguments& args) {
+ return Buffer::StringWrite<ASCII>(args);
+}
-// var charsWritten = buffer.asciiWrite(string, offset);
-Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
+template <encoding encoding>
+Handle<Value> Buffer::StringWrite(const Arguments& args) {
HandleScope scope;
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ Buffer* buffer = ObjectWrap::Unwrap<Buffer>(args.This());
if (!args[0]->IsString()) {
return ThrowTypeError("Argument must be a string");
}
- Local<String> s = args[0]->ToString();
- size_t length = s->Length();
- size_t offset = args[1]->Int32Value();
-
- if (length > 0 && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- char *p = buffer->data_ + offset;
-
- int written = s->WriteAscii(p,
- 0,
- max_length,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(written));
-
- return scope.Close(Integer::New(written));
-}
+ Local<String> str = args[0].As<String>();
+ if (encoding == HEX && str->Length() % 2 != 0)
+ return ThrowTypeError("Invalid hex string");
-// var bytesWritten = buffer.base64Write(string, offset, [maxLength]);
-Handle<Value> Buffer::Base64Write(const Arguments &args) {
- HandleScope scope;
-
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
- }
-
- String::AsciiValue s(args[0]);
- size_t length = s.length();
size_t offset = args[1]->Int32Value();
size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
: args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- if (max_length && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- char a, b, c, d;
- char* start = buffer->data_ + offset;
- char* dst = start;
- char* const dstEnd = dst + max_length;
- const char* src = *s;
- const char* const srcEnd = src + s.length();
-
- while (src < srcEnd && dst < dstEnd) {
- int remaining = srcEnd - src;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining == 0 || *src == '=') break;
- a = unbase64(*src++);
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 1 || *src == '=') break;
- b = unbase64(*src++);
-
- *dst++ = (a << 2) | ((b & 0x30) >> 4);
- if (dst == dstEnd) break;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 2 || *src == '=') break;
- c = unbase64(*src++);
-
- *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
- if (dst == dstEnd) break;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 3 || *src == '=') break;
- d = unbase64(*src++);
-
- *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
- }
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(dst - start));
-
- return scope.Close(Integer::New(dst - start));
-}
-
-
-Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
- HandleScope scope;
-
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ max_length = MIN(buffer->length_ - offset, max_length);
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
+ if (max_length == 0) {
+ // shortcut: nothing to write anyway
+ Local<Integer> val = Integer::New(0);
+ constructor_template->GetFunction()->Set(chars_written_sym, val);
+ return scope.Close(val);
}
- Local<String> s = args[0]->ToString();
- size_t length = s->Length();
- size_t offset = args[1]->Int32Value();
+ if (encoding == UCS2)
+ max_length = max_length / 2;
- if (s->Length() > 0 && offset >= buffer->length_) {
+ if (offset >= buffer->length_) {
return ThrowTypeError("Offset is out of bounds");
}
- char *p = (char*)buffer->data_ + offset;
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- int written = DecodeWrite(p, max_length, s, BINARY);
+ char* start = buffer->data_ + offset;
+ int chars_written;
+ size_t written = StringBytes::Write(start,
+ max_length,
+ str,
+ encoding,
+ &chars_written);
constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(written));
+ Integer::New(chars_written));
return scope.Close(Integer::New(written));
}
-
static bool is_big_endian() {
const union { uint8_t u8[2]; uint16_t u16; } u = {{0, 1}};
return u.u16 == 1 ? true : false;
@@ -973,7 +499,7 @@ Handle<Value> Buffer::WriteDoubleBE(const Arguments& args) {
// var nbytes = Buffer.byteLength("string", "utf8")
-Handle<Value> Buffer::ByteLength(const Arguments &args) {
+Handle<Value> Buffer::ByteLength(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsString()) {
@@ -983,11 +509,11 @@ Handle<Value> Buffer::ByteLength(const Arguments &args) {
Local<String> s = args[0]->ToString();
enum encoding e = ParseEncoding(args[1], UTF8);
- return scope.Close(Integer::New(node::ByteLength(s, e)));
+ return scope.Close(Integer::New(StringBytes::Size(s, e)));
}
-Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
+Handle<Value> Buffer::MakeFastBuffer(const Arguments& args) {
HandleScope scope;
if (!Buffer::HasInstance(args[0])) {
@@ -1102,17 +628,6 @@ RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle<Value> wrapper) {
void Buffer::Initialize(Handle<Object> target) {
HandleScope scope;
- // sanity checks
- 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);
-
length_symbol = NODE_PSYMBOL("length");
chars_written_sym = NODE_PSYMBOL("_charsWritten");
@@ -1121,15 +636,13 @@ void Buffer::Initialize(Handle<Object> target) {
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
- // 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, "ucs2Slice", Buffer::Ucs2Slice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "hexSlice", Buffer::HexSlice);
- // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
- // copy
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
+ // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
diff --git a/src/node_buffer.h b/src/node_buffer.h
index 5743f9b26..7b7cf8e58 100644
--- a/src/node_buffer.h
+++ b/src/node_buffer.h
@@ -113,12 +113,18 @@ class NODE_EXTERN Buffer: public ObjectWrap {
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
+
+ template <encoding encoding>
+ static v8::Handle<v8::Value> StringSlice(const v8::Arguments &args);
static v8::Handle<v8::Value> BinarySlice(const v8::Arguments &args);
static v8::Handle<v8::Value> AsciiSlice(const v8::Arguments &args);
static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> Ucs2Slice(const v8::Arguments &args);
static v8::Handle<v8::Value> HexSlice(const v8::Arguments &args);
+
+ template <encoding encoding>
+ static v8::Handle<v8::Value> StringWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Base64Write(const v8::Arguments &args);
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);