2323
2424#if defined(NODE_HAVE_I18N_SUPPORT)
2525
26+ #include " node.h"
27+ #include " env.h"
28+ #include " env-inl.h"
29+ #include " util.h"
30+ #include " util-inl.h"
31+ #include " v8.h"
32+
2633#include < unicode/putil.h>
2734#include < unicode/udata.h>
35+ #include < unicode/uidna.h>
2836
2937#ifdef NODE_HAVE_SMALL_ICU
3038/* if this is defined, we have a 'secondary' entry point.
@@ -43,6 +51,13 @@ extern "C" const char U_DATA_API SMALL_ICUDATA_ENTRY_POINT[];
4351
4452namespace node {
4553
54+ using v8::Context;
55+ using v8::FunctionCallbackInfo;
56+ using v8::Local;
57+ using v8::Object;
58+ using v8::String;
59+ using v8::Value;
60+
4661bool flag_icu_data_dir = false ;
4762
4863namespace i18n {
@@ -64,7 +79,124 @@ bool InitializeICUDirectory(const char* icu_data_path) {
6479 }
6580}
6681
82+ static int32_t ToUnicode (MaybeStackBuffer<char >* buf,
83+ const char * input,
84+ size_t length) {
85+ UErrorCode status = U_ZERO_ERROR;
86+ uint32_t options = UIDNA_DEFAULT;
87+ options |= UIDNA_NONTRANSITIONAL_TO_UNICODE;
88+ UIDNA* uidna = uidna_openUTS46 (options, &status);
89+ if (U_FAILURE (status))
90+ return -1 ;
91+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
92+
93+ int32_t len = uidna_nameToUnicodeUTF8 (uidna,
94+ input, length,
95+ **buf, buf->length (),
96+ &info,
97+ &status);
98+
99+ if (status == U_BUFFER_OVERFLOW_ERROR) {
100+ status = U_ZERO_ERROR;
101+ buf->AllocateSufficientStorage (len);
102+ len = uidna_nameToUnicodeUTF8 (uidna,
103+ input, length,
104+ **buf, buf->length (),
105+ &info,
106+ &status);
107+ }
108+
109+ if (U_FAILURE (status))
110+ len = -1 ;
111+
112+ uidna_close (uidna);
113+ return len;
114+ }
115+
116+ static int32_t ToASCII (MaybeStackBuffer<char >* buf,
117+ const char * input,
118+ size_t length) {
119+ UErrorCode status = U_ZERO_ERROR;
120+ uint32_t options = UIDNA_DEFAULT;
121+ options |= UIDNA_NONTRANSITIONAL_TO_ASCII;
122+ UIDNA* uidna = uidna_openUTS46 (options, &status);
123+ if (U_FAILURE (status))
124+ return -1 ;
125+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
126+
127+ int32_t len = uidna_nameToASCII_UTF8 (uidna,
128+ input, length,
129+ **buf, buf->length (),
130+ &info,
131+ &status);
132+
133+ if (status == U_BUFFER_OVERFLOW_ERROR) {
134+ status = U_ZERO_ERROR;
135+ buf->AllocateSufficientStorage (len);
136+ len = uidna_nameToASCII_UTF8 (uidna,
137+ input, length,
138+ **buf, buf->length (),
139+ &info,
140+ &status);
141+ }
142+
143+ if (U_FAILURE (status))
144+ len = -1 ;
145+
146+ uidna_close (uidna);
147+ return len;
148+ }
149+
150+ static void ToUnicode (const FunctionCallbackInfo<Value>& args) {
151+ Environment* env = Environment::GetCurrent (args);
152+ CHECK_GE (args.Length (), 1 );
153+ CHECK (args[0 ]->IsString ());
154+ Utf8Value val (env->isolate (), args[0 ]);
155+ MaybeStackBuffer<char > buf;
156+ int32_t len = ToUnicode (&buf, *val, val.length ());
157+
158+ if (len < 0 ) {
159+ return env->ThrowError (" Cannot convert name to Unicode" );
160+ }
161+
162+ args.GetReturnValue ().Set (
163+ String::NewFromUtf8 (env->isolate (),
164+ *buf,
165+ v8::NewStringType::kNormal ,
166+ len).ToLocalChecked ());
167+ }
168+
169+ static void ToASCII (const FunctionCallbackInfo<Value>& args) {
170+ Environment* env = Environment::GetCurrent (args);
171+ CHECK_GE (args.Length (), 1 );
172+ CHECK (args[0 ]->IsString ());
173+ Utf8Value val (env->isolate (), args[0 ]);
174+ MaybeStackBuffer<char > buf;
175+ int32_t len = ToASCII (&buf, *val, val.length ());
176+
177+ if (len < 0 ) {
178+ return env->ThrowError (" Cannot convert name to ASCII" );
179+ }
180+
181+ args.GetReturnValue ().Set (
182+ String::NewFromUtf8 (env->isolate (),
183+ *buf,
184+ v8::NewStringType::kNormal ,
185+ len).ToLocalChecked ());
186+ }
187+
188+ void Init (Local<Object> target,
189+ Local<Value> unused,
190+ Local<Context> context,
191+ void * priv) {
192+ Environment* env = Environment::GetCurrent (context);
193+ env->SetMethod (target, " toUnicode" , ToUnicode);
194+ env->SetMethod (target, " toASCII" , ToASCII);
195+ }
196+
67197} // namespace i18n
68198} // namespace node
69199
200+ NODE_MODULE_CONTEXT_AWARE_BUILTIN (icu, node::i18n::Init)
201+
70202#endif // NODE_HAVE_I18N_SUPPORT
0 commit comments