Browse Source

string_bytes: write strings using new API

StringBytes::Write now uses new v8 API and also does preliminary check
if the string is external, then will use external memory instead.
v0.11.3-release
Trevor Norris 12 years ago
parent
commit
e92f4879eb
  1. 112
      src/string_bytes.cc
  2. 74
      test/simple/test-stringbytes-external.js

112
src/string_bytes.cc

@ -36,9 +36,9 @@
namespace node {
using v8::Local;
using v8::Handle;
using v8::HandleScope;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
@ -227,41 +227,65 @@ static inline size_t hex_decode(char* buf,
}
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:
@ -269,50 +293,38 @@ size_t StringBytes::Write(char* buf,
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");

74
test/simple/test-stringbytes-external.js

@ -0,0 +1,74 @@
// 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);
Loading…
Cancel
Save