namespace node {
-using v8::Local;
using v8::Handle;
using v8::HandleScope;
+using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
}
+bool GetExternalParts(Handle<Value> val, const char** data, size_t* len) {
+ if (Buffer::HasInstance(val)) {
+ *data = Buffer::Data(val);
+ *len = Buffer::Length(val);
+ return true;
+
+ }
+
+ assert(val->IsString());
+ Local<String> str = Local<String>::New(val.As<String>());
+
+ if (str->IsExternalAscii()) {
+ const String::ExternalAsciiStringResource* ext;
+ ext = str->GetExternalAsciiStringResource();
+ *data = ext->data();
+ *len = ext->length();
+ return true;
+
+ } else if (str->IsExternal()) {
+ const String::ExternalStringResource* ext;
+ ext = str->GetExternalStringResource();
+ *data = reinterpret_cast<const char*>(ext->data());
+ *len = ext->length();
+ return true;
+ }
+
+ return false;
+}
+
+
size_t StringBytes::Write(char* buf,
size_t buflen,
Handle<Value> val,
enum encoding encoding,
int* chars_written) {
-
HandleScope scope(node_isolate);
+ const char* data;
size_t len = 0;
- bool is_buffer = Buffer::HasInstance(val);
-
- // sometimes we use 'binary' when we mean 'buffer'
- if (is_buffer && (encoding == BINARY || encoding == BUFFER)) {
- // fast path, copy buffer data
- Local<Object> valObj = Local<Object>::New(val.As<Object>());
- const char* data = Buffer::Data(valObj);
- size_t size = Buffer::Length(valObj);
- size_t len = size < buflen ? size : buflen;
- memcpy(buf, data, len);
- return len;
- }
+ bool is_extern = GetExternalParts(val, &data, &len);
Local<String> str = val->ToString();
+ len = len < buflen ? len : buflen;
int flags = String::NO_NULL_TERMINATION |
String::HINT_MANY_WRITES_EXPECTED;
switch (encoding) {
case ASCII:
- len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
- 0,
- buflen,
- flags);
- if (chars_written != NULL) {
+ case BINARY:
+ case BUFFER:
+ if (is_extern)
+ memcpy(buf, data, len);
+ else
+ len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
+ 0,
+ buflen,
+ flags);
+ if (chars_written != NULL)
*chars_written = len;
- }
break;
case UTF8:
break;
case UCS2:
- len = str->Write(reinterpret_cast<uint16_t*>(buf), 0, buflen, flags);
- if (chars_written != NULL) {
+ if (is_extern)
+ memcpy(buf, data, len * 2);
+ else
+ len = str->Write(reinterpret_cast<uint16_t*>(buf), 0, buflen, flags);
+ if (chars_written != NULL)
*chars_written = len;
- }
len = len * sizeof(uint16_t);
break;
- case BASE64: {
- String::AsciiValue value(str);
- len = base64_decode(buf, buflen, *value, value.length());
- if (chars_written != NULL) {
- *chars_written = len;
- }
- break;
- }
-
- case BINARY:
- case BUFFER: {
- // TODO(isaacs): THIS IS AWFUL!!!
- uint16_t* twobytebuf = new uint16_t[buflen];
-
- len = str->Write(twobytebuf, 0, buflen, flags);
-
- for (size_t i = 0; i < buflen && i < len; i++) {
- unsigned char* b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
- buf[i] = b[0];
+ case BASE64:
+ if (is_extern) {
+ base64_decode(buf, buflen, data, len);
+ } else {
+ String::AsciiValue value(str);
+ len = base64_decode(buf, buflen, *value, value.length());
}
-
if (chars_written != NULL) {
*chars_written = len;
}
-
- delete[] twobytebuf;
break;
- }
- case HEX: {
- String::AsciiValue value(str);
- len = hex_decode(buf, buflen, *value, value.length());
+ case HEX:
+ if (is_extern) {
+ hex_decode(buf, buflen, data, len);
+ } else {
+ String::AsciiValue value(str);
+ len = hex_decode(buf, buflen, *value, value.length());
+ }
if (chars_written != NULL) {
*chars_written = len * 2;
}
break;
- }
default:
assert(0 && "unknown encoding");
--- /dev/null
+// 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 common = require('../common');
+var assert = require('assert');
+// minimum string size to overflow into external string space
+var EXTERN_APEX = 0xFBEE9;
+
+// manually controlled string for checking binary output
+var ucs2_control = 'a\u0000';
+var write_str = 'a';
+
+
+// first do basic checks
+var b = new Buffer(write_str, 'ucs2');
+var c = b.toString('binary');
+assert.equal(b[0], 0x61);
+assert.equal(b[1], 0);
+assert.equal(ucs2_control, c);
+
+
+// grow the strings to proper length
+while (write_str.length <= EXTERN_APEX) {
+ write_str += write_str;
+ ucs2_control += ucs2_control;
+}
+write_str += write_str.substr(0, EXTERN_APEX - write_str.length);
+ucs2_control += ucs2_control.substr(0, EXTERN_APEX * 2 - ucs2_control.length);
+
+
+// check resultant buffer and output string
+var b = new Buffer(write_str, 'ucs2');
+// check fist Buffer created from write string
+for (var i = 0; i < b.length; i += 2) {
+ assert.equal(b[i], 0x61);
+ assert.equal(b[i + 1], 0);
+}
+// create another string to create an external string
+var b_bin = b.toString('binary');
+var b_ucs = b.toString('ucs2');
+// check control against external binary string
+assert.equal(ucs2_control, b_bin);
+// create buffer copy from external
+var c_bin = new Buffer(b_bin, 'binary');
+var c_ucs = new Buffer(b_ucs, 'ucs2');
+// make sure they're the same length
+assert.equal(c_bin.length, c_ucs.length);
+// make sure Buffers from externals are the same
+for (var i = 0; i < c_bin.length; i++) {
+ assert.equal(c_bin[i], c_ucs[i], c_bin[i] + ' == ' + c_ucs[i] +
+ ' : index ' + i);
+}
+// check resultant strings
+assert.equal(c_bin.toString('ucs2'), c_ucs.toString('ucs2'));
+assert.equal(c_bin.toString('binary'), ucs2_control);
+assert.equal(c_ucs.toString('binary'), ucs2_control);