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()); ChildProcess *child = ObjectWrap::Unwrap<ChildProcess>(args.Holder());
assert(child); assert(child);
ssize_t len; enum encoding enc = ParseEncoding(args[1]);
ssize_t len = DecodeBytes(args[0], enc);
Local<String> string; if (len < 0) {
Local<Array> array; Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
if (args[0]->IsArray()) {
array = Local<Array>::Cast(args[0]);
len = array->Length();
} else {
string = args[0]->ToString();
len = string->Utf8Length();
} }
char buf[len]; char buf[len];
ssize_t written = DecodeWrite(buf, len, args[0], enc);
if (args[0]->IsArray()) {
for (ssize_t index = 0; index < len; index++) { assert(written == len);
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."));
}
}
return child->Write(buf, len) == 0 ? True() : False(); 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; HandleScope scope;
bool isSTDOUT = (r == &child->stdout_reader_); bool isSTDOUT = (r == &child->stdout_reader_);
Local<Value> argv[1];
enum encoding encoding = isSTDOUT ? child->stdout_encoding_ : child->stderr_encoding_; enum encoding encoding = isSTDOUT ? child->stdout_encoding_ : child->stderr_encoding_;
if (len == 0) { Local<Value> data = Encode(buf, len, encoding);
argv[0] = Local<Value>::New(Null()); child->Emit(isSTDOUT ? "output" : "error", 1, &data);
} 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);
child->MaybeShutdown(); child->MaybeShutdown();
} }

61
src/file.cc

@ -116,34 +116,8 @@ EIOPromise::After (eio_req *req)
case EIO_READ: case EIO_READ:
{ {
argc = 2; argc = 2;
// FIXME the following is really ugly! argv[0] = Encode(req->ptr2, req->result, promise->encoding_);
if (promise->encoding_ == RAW) { argv[1] = Integer::New(req->result);
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);
}
}
break; break;
} }
@ -304,6 +278,7 @@ Open (const Arguments& args)
* 1 data the data to write (string = utf8, array = raw) * 1 data the data to write (string = utf8, array = raw)
* 2 position if integer, position to write at in the file. * 2 position if integer, position to write at in the file.
* if null, write from the current position * if null, write from the current position
* 3 encoding
*/ */
static Handle<Value> static Handle<Value>
Write (const Arguments& args) Write (const Arguments& args)
@ -317,29 +292,15 @@ Write (const Arguments& args)
int fd = args[0]->Int32Value(); int fd = args[0]->Int32Value();
off_t offset = args[2]->IsNumber() ? args[2]->IntegerValue() : -1; off_t offset = args[2]->IsNumber() ? args[2]->IntegerValue() : -1;
char *buf = NULL; enum encoding enc = ParseEncoding(args[3]);
size_t len = 0; ssize_t len = DecodeBytes(args[1], enc);
if (len < 0) {
if (args[1]->IsString()) { Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
// utf8 encoding return ThrowException(exception);
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);
} }
char buf[len];
ssize_t written = DecodeWrite(buf, len, args[1], enc);
assert(written == len);
return scope.Close(EIOPromise::Write(fd, buf, len, offset)); 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); return ThrowException(exception);
} }
// XXX enum encoding enc = ParseEncoding(args[1]);
// A lot of improvement can be made here. First of all we're allocating ssize_t len = DecodeBytes(args[0], enc);
// 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);
} else { if (len < 0) {
Local<Value> exception = Exception::TypeError(String::New("Bad argument")); Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception); 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 void
Connection::OnReceive (const void *buf, size_t len) Connection::OnReceive (const void *buf, size_t len)
{ {
HandleScope scope; HandleScope scope;
Local<Value> data = Encode(buf, len, encoding_);
const int argc = 1; Emit("receive", 1, &data);
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);
} }
void void

83
src/node.cc

@ -30,6 +30,89 @@
using namespace v8; using namespace v8;
using namespace node; 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. // Extracts a C string from a V8 Utf8Value.
const char* const char*
ToCString(const v8::String::Utf8Value& value) 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); enum encoding ParseEncoding (v8::Handle<v8::Value> encoding_v);
void FatalException (v8::TryCatch &try_catch); 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 } // namespace node
#endif // node_h #endif // node_h

57
src/node_stdio.cc

@ -67,41 +67,18 @@ Write (const Arguments& args)
{ {
HandleScope scope; HandleScope scope;
ssize_t len; enum encoding enc = ParseEncoding(args[1]);
ssize_t len = DecodeBytes(args[0], enc);
Local<String> string; if (len < 0) {
Local<Array> array; Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
return ThrowException(exception);
if (args[0]->IsArray()) {
array = Local<Array>::Cast(args[0]);
len = array->Length();
} else {
string = args[0]->ToString();
len = string->Utf8Length();
} }
char buf[len]; char buf[len];
ssize_t written = DecodeWrite(buf, len, args[0], enc);
if (args[0]->IsArray()) {
for (ssize_t index = 0; index < len; index++) { assert(written == len);
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."));
}
}
evcom_writer_write(&out, buf, len); evcom_writer_write(&out, buf, len);
@ -149,23 +126,9 @@ on_read (evcom_reader *r, const void *buf, size_t len)
return; return;
} }
Local<Value> input; Local<Value> data = Encode(buf, len, stdin_encoding);
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);
}
EmitInput(input); EmitInput(data);
} }
static inline int static inline int

Loading…
Cancel
Save