Browse Source

Byte stream to V8 decoding and encoding.

This does not (should not) change behavior.  Pulls those two functions
(encode/decode) out into node.cc.
v0.7.4-release
Ryan 16 years ago
parent
commit
21a1b045f5
  1. 61
      src/child_process.cc
  2. 61
      src/file.cc
  3. 76
      src/net.cc
  4. 83
      src/node.cc
  5. 12
      src/node.h
  6. 57
      src/node_stdio.cc

61
src/child_process.cc

@ -73,41 +73,18 @@ ChildProcess::Write (const Arguments& args)
ChildProcess *child = ObjectWrap::Unwrap<ChildProcess>(args.Holder());
assert(child);
ssize_t len;
enum encoding enc = ParseEncoding(args[1]);
ssize_t len = DecodeBytes(args[0], enc);
Local<String> string;
Local<Array> array;
if (args[0]->IsArray()) {
array = Local<Array>::Cast(args[0]);
len = array->Length();
} else {
string = args[0]->ToString();
len = string->Utf8Length();
if (len < 0) {
Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
}
char buf[len];
if (args[0]->IsArray()) {
for (ssize_t index = 0; index < len; index++) {
Local<Value> int_value = array->Get(Integer::New(index));
buf[index] = int_value->IntegerValue();
}
} else {
switch (ParseEncoding(args[1])) {
case RAW:
case ASCII:
string->WriteAscii(buf, 0, len);
break;
case UTF8:
string->WriteUtf8(buf, len);
break;
default:
return ThrowException(String::New("Unknown encoding."));
}
}
ssize_t written = DecodeWrite(buf, len, args[0], enc);
assert(written == len);
return child->Write(buf, len) == 0 ? True() : False();
}
@ -169,28 +146,10 @@ ChildProcess::on_read (evcom_reader *r, const void *buf, size_t len)
HandleScope scope;
bool isSTDOUT = (r == &child->stdout_reader_);
Local<Value> argv[1];
enum encoding encoding = isSTDOUT ? child->stdout_encoding_ : child->stderr_encoding_;
if (len == 0) {
argv[0] = Local<Value>::New(Null());
} else if (encoding == RAW) {
// raw encoding
Local<Array> array = Array::New(len);
for (size_t i = 0; i < len; i++) {
unsigned char val = static_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
argv[0] = array;
} else {
// utf8 or ascii encoding
argv[0] = String::New((const char*)buf, len);
}
child->Emit(isSTDOUT ? "output" : "error", 1, argv);
Local<Value> data = Encode(buf, len, encoding);
child->Emit(isSTDOUT ? "output" : "error", 1, &data);
child->MaybeShutdown();
}

61
src/file.cc

@ -116,34 +116,8 @@ EIOPromise::After (eio_req *req)
case EIO_READ:
{
argc = 2;
// FIXME the following is really ugly!
if (promise->encoding_ == RAW) {
if (req->result == 0) {
argv[0] = Local<Value>::New(Null());
argv[1] = Integer::New(0);
} else {
char *buf = reinterpret_cast<char*>(req->ptr2);
size_t len = req->result;
Local<Array> array = Array::New(len);
for (unsigned int i = 0; i < len; i++) {
unsigned char val = reinterpret_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
argv[0] = array;
argv[1] = Integer::New(req->result);
}
} else {
// UTF8
if (req->result == 0) {
// eof
argv[0] = Local<Value>::New(Null());
argv[1] = Integer::New(0);
} else {
char *buf = reinterpret_cast<char*>(req->ptr2);
argv[0] = String::New(buf, req->result);
argv[1] = Integer::New(req->result);
}
}
argv[0] = Encode(req->ptr2, req->result, promise->encoding_);
argv[1] = Integer::New(req->result);
break;
}
@ -304,6 +278,7 @@ Open (const Arguments& args)
* 1 data the data to write (string = utf8, array = raw)
* 2 position if integer, position to write at in the file.
* if null, write from the current position
* 3 encoding
*/
static Handle<Value>
Write (const Arguments& args)
@ -317,29 +292,15 @@ Write (const Arguments& args)
int fd = args[0]->Int32Value();
off_t offset = args[2]->IsNumber() ? args[2]->IntegerValue() : -1;
char *buf = NULL;
size_t len = 0;
if (args[1]->IsString()) {
// utf8 encoding
Local<String> string = args[1]->ToString();
len = string->Utf8Length();
buf = reinterpret_cast<char*>(malloc(len));
string->WriteUtf8(buf, len);
} else if (args[1]->IsArray()) {
// raw encoding
Local<Array> array = Local<Array>::Cast(args[1]);
len = array->Length();
buf = reinterpret_cast<char*>(malloc(len));
for (unsigned int i = 0; i < len; i++) {
Local<Value> int_value = array->Get(Integer::New(i));
buf[i] = int_value->Int32Value();
}
} else {
return ThrowException(BAD_ARGUMENTS);
enum encoding enc = ParseEncoding(args[3]);
ssize_t len = DecodeBytes(args[1], enc);
if (len < 0) {
Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
}
char buf[len];
ssize_t written = DecodeWrite(buf, len, args[1], enc);
assert(written == len);
return scope.Close(EIOPromise::Write(fd, buf, len, offset));
}

76
src/net.cc

@ -374,80 +374,30 @@ Connection::Send (const Arguments& args)
return ThrowException(exception);
}
// XXX
// A lot of improvement can be made here. First of all we're allocating
// evcom_bufs for every send which is clearly inefficent - it should use a
// memory pool or ring buffer. Of course, expressing binary data as an
// array of integers is extremely inefficent. This can improved when v8
// bug 270 (http://code.google.com/p/v8/issues/detail?id=270) has been
// addressed.
if (args[0]->IsString()) {
enum encoding enc = ParseEncoding(args[1]);
Local<String> s = args[0]->ToString();
size_t len = s->Utf8Length();
char buf[len];
switch (enc) {
case RAW:
case ASCII:
s->WriteAscii(buf, 0, len);
break;
case UTF8:
s->WriteUtf8(buf, len);
break;
default:
assert(0 && "unhandled string encoding");
}
connection->Send(buf, len);
} else if (args[0]->IsArray()) {
Handle<Array> array = Handle<Array>::Cast(args[0]);
size_t len = array->Length();
char buf[len];
for (size_t i = 0; i < len; i++) {
Local<Value> int_value = array->Get(Integer::New(i));
buf[i] = int_value->IntegerValue();
}
connection->Send(buf, len);
enum encoding enc = ParseEncoding(args[1]);
ssize_t len = DecodeBytes(args[0], enc);
} else {
if (len < 0) {
Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
}
return Undefined();
char buf[len];
ssize_t written = DecodeWrite(buf, len, args[0], enc);
assert(written == len);
connection->Send(buf, written);
return scope.Close(Integer::New(written));
}
void
Connection::OnReceive (const void *buf, size_t len)
{
HandleScope scope;
const int argc = 1;
Handle<Value> argv[argc];
if(len) {
if (encoding_ == RAW) {
// raw encoding
Local<Array> array = Array::New(len);
for (size_t i = 0; i < len; i++) {
unsigned char val = static_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
argv[0] = array;
} else {
// utf8 or ascii encoding
Handle<String> chunk = String::New((const char*)buf, len);
argv[0] = chunk;
}
} else {
argv[0] = Local<Value>::New(Null());
}
Emit("receive", argc, argv);
Local<Value> data = Encode(buf, len, encoding_);
Emit("receive", 1, &data);
}
void

83
src/node.cc

@ -30,6 +30,89 @@
using namespace v8;
using namespace node;
Local<Value>
node::Encode (const void *buf, size_t len, enum encoding encoding)
{
HandleScope scope;
if (!len) return scope.Close(Null());
if (encoding == RAW) {
// raw encoding
Local<Array> array = Array::New(len);
for (size_t i = 0; i < len; i++) {
unsigned char val = static_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
return scope.Close(array);
}
// utf8 or ascii encoding
Local<String> chunk = String::New((const char*)buf, len);
return scope.Close(chunk);
}
// Returns -1 if the handle was not valid for decoding
ssize_t
node::DecodeBytes (v8::Handle<v8::Value> val, enum encoding encoding)
{
HandleScope scope;
if (val->IsArray()) {
if (encoding != RAW) return -1;
Handle<Array> array = Handle<Array>::Cast(val);
return array->Length();
}
if (!val->IsString()) return -1;
Handle<String> string = Handle<String>::Cast(val);
if (encoding == UTF8) return string->Utf8Length();
return string->Length();
}
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
// Returns number of bytes written.
ssize_t
node::DecodeWrite (char *buf, size_t buflen, v8::Handle<v8::Value> val, enum encoding encoding)
{
size_t i;
HandleScope scope;
// XXX
// A lot of improvement can be made here. See:
// http://code.google.com/p/v8/issues/detail?id=270
// http://groups.google.com/group/v8-dev/browse_thread/thread/dba28a81d9215291/ece2b50a3b4022c
// http://groups.google.com/group/v8-users/browse_thread/thread/1f83b0ba1f0a611
if (val->IsArray()) {
if (encoding != RAW) return -1;
Handle<Array> array = Handle<Array>::Cast(val);
size_t array_len = array->Length();
for (i = 0; i < MIN(buflen, array_len); i++) {
Local<Value> int_value = array->Get(Integer::New(i));
buf[i] = int_value->IntegerValue();
}
return i;
}
assert(val->IsString());
Handle<String> string = Handle<String>::Cast(val);
if (encoding == UTF8) {
string->WriteUtf8(buf, buflen);
return buflen;
}
string->WriteAscii(buf, 0, buflen);
return buflen;
}
// Extracts a C string from a V8 Utf8Value.
const char*
ToCString(const v8::String::Utf8Value& value)

12
src/node.h

@ -36,5 +36,17 @@ enum encoding {ASCII, UTF8, RAW};
enum encoding ParseEncoding (v8::Handle<v8::Value> encoding_v);
void FatalException (v8::TryCatch &try_catch);
v8::Local<v8::Value>
Encode (const void *buf, size_t len, enum encoding encoding = RAW);
// Returns -1 if the handle was not valid for decoding
ssize_t
DecodeBytes (v8::Handle<v8::Value>, enum encoding encoding = RAW);
// returns bytes written.
ssize_t
DecodeWrite (char *buf, size_t buflen, v8::Handle<v8::Value>, enum encoding encoding = RAW);
} // namespace node
#endif // node_h

57
src/node_stdio.cc

@ -67,41 +67,18 @@ Write (const Arguments& args)
{
HandleScope scope;
ssize_t len;
enum encoding enc = ParseEncoding(args[1]);
ssize_t len = DecodeBytes(args[0], enc);
Local<String> string;
Local<Array> array;
if (args[0]->IsArray()) {
array = Local<Array>::Cast(args[0]);
len = array->Length();
} else {
string = args[0]->ToString();
len = string->Utf8Length();
if (len < 0) {
Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
}
char buf[len];
if (args[0]->IsArray()) {
for (ssize_t index = 0; index < len; index++) {
Local<Value> int_value = array->Get(Integer::New(index));
buf[index] = int_value->IntegerValue();
}
} else {
switch (ParseEncoding(args[1])) {
case RAW:
case ASCII:
string->WriteAscii(buf, 0, len);
break;
case UTF8:
string->WriteUtf8(buf, len);
break;
default:
return ThrowException(String::New("Unknown encoding."));
}
}
ssize_t written = DecodeWrite(buf, len, args[0], enc);
assert(written == len);
evcom_writer_write(&out, buf, len);
@ -149,23 +126,9 @@ on_read (evcom_reader *r, const void *buf, size_t len)
return;
}
Local<Value> input;
if (stdin_encoding == RAW) {
// raw encoding
Local<Array> array = Array::New(len);
for (size_t i = 0; i < len; i++) {
unsigned char val = static_cast<const unsigned char*>(buf)[i];
array->Set(Integer::New(i), Integer::New(val));
}
input = array;
} else {
// utf8 or ascii encoding
input = String::New((const char*)buf, len);
}
Local<Value> data = Encode(buf, len, stdin_encoding);
EmitInput(input);
EmitInput(data);
}
static inline int

Loading…
Cancel
Save