Open Chinese Convert  0.4.3
A project for conversion between Traditional and Simplified Chinese
 All Data Structures Files Functions Variables Groups Pages
binding.cc
1 #include <iostream>
2 #include <node.h>
3 #include <v8.h>
4 #include "../src/opencc.h"
5 
6 using namespace v8;
7 
8 char* ToUtf8String(const Local<String>& str) {
9  char* utf8 = new char[str->Utf8Length() + 1];
10  utf8[str->Utf8Length()] = '\0';
11  str->WriteUtf8(utf8);
12  return utf8;
13 }
14 
15 class OpenccBinding : public node::ObjectWrap {
16  struct ConvertRequest {
17  OpenccBinding* opencc_instance;
18  char* input;
19  char* output;
20  Persistent<Function> callback;
21  };
22  public:
23  explicit OpenccBinding(const char * config_file) {
24  handler_ = opencc_open(config_file);
25  }
26 
27  virtual ~OpenccBinding() {
28  if (handler_ != (opencc_t) -1)
29  opencc_close(handler_);
30  }
31 
32  operator bool() const {
33  return handler_ != (opencc_t) -1;
34  }
35 
36  static Handle<Value> New(const Arguments& args) {
37  HandleScope scope;
38  OpenccBinding* opencc_instance;
39 
40  if (args.Length() >= 1 && args[0]->IsString()) {
41  char* config_file = ToUtf8String(args[0]->ToString());
42  opencc_instance = new OpenccBinding(config_file);
43  delete[] config_file;
44  } else {
45  const char* config_file = OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD;
46  opencc_instance = new OpenccBinding(config_file);
47  }
48 
49  if (!*opencc_instance) {
50  ThrowException(Exception::Error(
51  String::New("Can not create opencc instance")));
52  return scope.Close(Undefined());
53  }
54  opencc_instance->Wrap(args.This());
55  return args.This();
56  }
57 
58  static Handle<Value> Convert(const Arguments& args) {
59  HandleScope scope;
60  if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsFunction()) {
61  ThrowException(Exception::TypeError(String::New("Wrong arguments")));
62  return scope.Close(Undefined());
63  }
64 
65  ConvertRequest* conv_data = new ConvertRequest;
66  conv_data->opencc_instance = ObjectWrap::Unwrap<OpenccBinding>(args.This());
67  conv_data->input = ToUtf8String(args[0]->ToString());
68  conv_data->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
69  uv_work_t* req = new uv_work_t;
70  req->data = conv_data;
71  uv_queue_work(uv_default_loop(), req, DoConnect, (uv_after_work_cb)AfterConvert);
72 
73  return Undefined();
74  }
75 
76  static void DoConnect(uv_work_t* req) {
77  ConvertRequest* conv_data = static_cast<ConvertRequest*>(req->data);
78  opencc_t opencc_handler = conv_data->opencc_instance->handler_;
79  conv_data->output = opencc_convert_utf8(opencc_handler, conv_data->input, (size_t) -1);
80  }
81 
82  static void AfterConvert(uv_work_t* req) {
83  HandleScope scope;
84  ConvertRequest* conv_data = static_cast<ConvertRequest*>(req->data);
85  Local<String> converted = String::New(conv_data->output);
86  const unsigned argc = 2;
87  Local<Value> argv[argc] = {
88  Local<Value>::New(Undefined()),
89  Local<Value>::New(converted)
90  };
91  conv_data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
92  conv_data->callback.Dispose();
93  delete[] conv_data->input;
94  opencc_convert_utf8_free(conv_data->output);
95  delete conv_data;
96  delete req;
97  }
98 
99  static Handle<Value> ConvertSync(const Arguments& args) {
100  HandleScope scope;
101  if (args.Length() < 1 || !args[0]->IsString()) {
102  ThrowException(Exception::TypeError(String::New("Wrong arguments")));
103  return scope.Close(Undefined());
104  }
105 
106  OpenccBinding* opencc_instance = ObjectWrap::Unwrap<OpenccBinding>(args.This());
107  opencc_t opencc_handler = opencc_instance->handler_;
108  char* input = ToUtf8String(args[0]->ToString());
109  char* output = opencc_convert_utf8(opencc_handler, input, (size_t) -1);
110 
111  Local<String> converted = String::New(output);
112  delete[] input;
113  opencc_convert_utf8_free(output);
114  return scope.Close(converted);
115  }
116 
117  static Handle<Value> SetConversionMode(const Arguments& args) {
118  HandleScope scope;
119  if (args.Length() < 1 || !args[0]->IsInt32()) {
120  ThrowException(Exception::TypeError(String::New("Wrong arguments")));
121  return scope.Close(Undefined());
122  }
123 
124  OpenccBinding* opencc_instance = ObjectWrap::Unwrap<OpenccBinding>(args.This());
125  opencc_t opencc_handler = opencc_instance->handler_;
126  int conversion_mode = args[0]->ToInt32()->Value();
127  if (conversion_mode < 0 || conversion_mode > 2) {
128  ThrowException(Exception::Error(
129  String::New("conversion_mode must between 0 and 2")));
130  return scope.Close(Undefined());
131  }
132 
133  opencc_set_conversion_mode(opencc_handler,
134  (opencc_conversion_mode) conversion_mode);
135  return scope.Close(Boolean::New(true));
136  }
137 
138  static void init(Handle<Object> target) {
139  // Prepare constructor template
140  Local<FunctionTemplate> tpl = FunctionTemplate::New(OpenccBinding::New);
141  tpl->SetClassName(String::NewSymbol("Opencc"));
142  tpl->InstanceTemplate()->SetInternalFieldCount(1);
143  // Prototype
144  tpl->PrototypeTemplate()->Set(String::NewSymbol("convert"),
145  FunctionTemplate::New(Convert)->GetFunction());
146  tpl->PrototypeTemplate()->Set(String::NewSymbol("convertSync"),
147  FunctionTemplate::New(ConvertSync)->GetFunction());
148  tpl->PrototypeTemplate()->Set(String::NewSymbol("setConversionMode"),
149  FunctionTemplate::New(SetConversionMode)->GetFunction());
150  // Constructor
151  Persistent<Function> constructor = Persistent<Function>::New(
152  tpl->GetFunction());
153  target->Set(String::NewSymbol("Opencc"), constructor);
154  }
155 
156  opencc_t handler_;
157 };
158 
159 void init(Handle<Object> target) {
160  OpenccBinding::init(target);
161 }
162 
163 NODE_MODULE(binding, init);