Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
UCS-2 support
Browse files Browse the repository at this point in the history
Closes GH-644.
  • Loading branch information
kkaefer authored and ry committed Feb 7, 2011
1 parent bf8f4aa commit 9e101f2
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 2 deletions.
17 changes: 17 additions & 0 deletions lib/buffer.js
Expand Up @@ -41,6 +41,10 @@ SlowBuffer.prototype.toString = function(encoding, start, end) {
case 'base64':
return this.base64Slice(start, end);

case 'ucs2':
case 'ucs-2':
return this.ucs2Slice(start, end);

default:
throw new Error('Unknown encoding');
}
Expand Down Expand Up @@ -73,6 +77,10 @@ SlowBuffer.prototype.write = function(string, offset, encoding) {
case 'base64':
return this.base64Write(string, offset);

case 'ucs2':
case 'ucs-2':
return this.ucs2Write(start, end);

default:
throw new Error('Unknown encoding');
}
Expand Down Expand Up @@ -228,6 +236,11 @@ Buffer.prototype.write = function(string, offset, encoding) {
ret = this.parent.base64Write(string, this.offset + offset, maxLength);
break;

case 'ucs2':
case 'ucs-2':
ret = this.parent.ucs2Write(string, this.offset + offset, maxLength);
break;

default:
throw new Error('Unknown encoding');
}
Expand Down Expand Up @@ -271,6 +284,10 @@ Buffer.prototype.toString = function(encoding, start, end) {
case 'base64':
return this.parent.base64Slice(start, end);

case 'ucs2':
case 'ucs-2':
return this.parent.ucs2Slice(start, end);

default:
throw new Error('Unknown encoding');
}
Expand Down
5 changes: 5 additions & 0 deletions src/node.cc
Expand Up @@ -1078,6 +1078,10 @@ enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
return ASCII;
} else if (strcasecmp(*encoding, "base64") == 0) {
return BASE64;
} else if (strcasecmp(*encoding, "ucs2") == 0) {
return UCS2;
} else if (strcasecmp(*encoding, "ucs-2") == 0) {
return UCS2;
} else if (strcasecmp(*encoding, "binary") == 0) {
return BINARY;
} else if (strcasecmp(*encoding, "raw") == 0) {
Expand Down Expand Up @@ -1129,6 +1133,7 @@ ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
Local<String> str = val->ToString();

if (encoding == UTF8) return str->Utf8Length();
else if (encoding == UCS2) return str->Length() * 2;

return str->Length();
}
Expand Down
2 changes: 1 addition & 1 deletion src/node.h
Expand Up @@ -44,7 +44,7 @@ do { \
__callback##_TEM); \
} while (0)

enum encoding {ASCII, UTF8, BASE64, BINARY};
enum encoding {ASCII, UTF8, BASE64, UCS2, BINARY};
enum encoding ParseEncoding(v8::Handle<v8::Value> encoding_v,
enum encoding _default = BINARY);
void FatalException(v8::TryCatch &try_catch);
Expand Down
46 changes: 46 additions & 0 deletions src/node_buffer.cc
Expand Up @@ -84,6 +84,8 @@ static size_t ByteLength (Handle<String> string, enum encoding enc) {
} else if (enc == BASE64) {
String::Utf8Value v(string);
return base64_decoded_size(*v, v.length());
} else if (enc == UCS2) {
return string->Length() * 2;
} else {
return string->Length();
}
Expand Down Expand Up @@ -245,6 +247,15 @@ Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
return scope.Close(string);
}

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);
}

static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
Expand Down Expand Up @@ -441,6 +452,39 @@ Handle<Value> Buffer::Utf8Write(const Arguments &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 ThrowException(Exception::TypeError(String::New(
"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);

uint16_t* p = (uint16_t*)(buffer->data_ + offset);

int written = s->Write(p,
0,
max_length,
String::HINT_MANY_WRITES_EXPECTED);
return scope.Close(Integer::New(written * 2));
}


// var charsWritten = buffer.asciiWrite(string, offset);
Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
HandleScope scope;
Expand Down Expand Up @@ -652,6 +696,7 @@ void Buffer::Initialize(Handle<Object> target) {
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);
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
// copy
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
Expand All @@ -660,6 +705,7 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);

NODE_SET_METHOD(constructor_template->GetFunction(),
Expand Down
2 changes: 2 additions & 0 deletions src/node_buffer.h
Expand Up @@ -88,10 +88,12 @@ class Buffer : public ObjectWrap {
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> 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);
static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
static v8::Handle<v8::Value> Ucs2Write(const v8::Arguments &args);
static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);
static v8::Handle<v8::Value> MakeFastBuffer(const v8::Arguments &args);
static v8::Handle<v8::Value> Copy(const v8::Arguments &args);
Expand Down
10 changes: 9 additions & 1 deletion test/simple/test-buffer.js
Expand Up @@ -225,6 +225,14 @@ var f = new Buffer('über', 'ascii');
console.error('f.length: %d (should be 4)', f.length);
assert.deepEqual(f, new Buffer([252, 98, 101, 114]));

var f = new Buffer('über', 'ucs2');
console.error('f.length: %d (should be 8)', f.length);
assert.deepEqual(f, new Buffer([252, 0, 98, 0, 101, 0, 114, 0]));

var f = new Buffer('привет', 'ucs2');
console.error('f.length: %d (should be 12)', f.length);
assert.deepEqual(f, new Buffer([63, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66, 4]));
assert.equal(f.toString('ucs2'), 'привет');

//
// Test toString('base64')
Expand Down Expand Up @@ -386,9 +394,9 @@ assert.equal('bcde', b.slice(1).toString());
// byte length
assert.equal(14, Buffer.byteLength('Il était tué'));
assert.equal(14, Buffer.byteLength('Il était tué', 'utf8'));
assert.equal(24, Buffer.byteLength('Il était tué', 'ucs2'));
assert.equal(12, Buffer.byteLength('Il était tué', 'ascii'));
assert.equal(12, Buffer.byteLength('Il était tué', 'binary'));


// slice(0,0).length === 0
assert.equal(0, Buffer('hello').slice(0, 0).length);

0 comments on commit 9e101f2

Please sign in to comment.