diff options
author | James M Snell <jasnell@gmail.com> | 2016-06-21 14:03:05 -0700 |
---|---|---|
committer | Jeremiah Senkpiel <fishrock123@rocketmail.com> | 2016-07-05 22:36:51 +0200 |
commit | d0e24923a69326b23ac14cc631724fc537521f9e (patch) | |
tree | d1d251811a1c2aaec20446acff679a65eb2fe2d3 /src/node_i18n.cc | |
parent | 12b199369d08cd4c09120411a173dbfba48521f8 (diff) | |
download | node-new-d0e24923a69326b23ac14cc631724fc537521f9e.tar.gz |
net: use icu's punycode implementation
ICU has a punycode implementation built in. Use it instead of the
javascript implementation because it's much faster.
PR-URL: https://github.com/nodejs/node/pull/7355
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'src/node_i18n.cc')
-rw-r--r-- | src/node_i18n.cc | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 3e5b3a9129..0f3b9b76e6 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -23,8 +23,16 @@ #if defined(NODE_HAVE_I18N_SUPPORT) +#include "node.h" +#include "env.h" +#include "env-inl.h" +#include "util.h" +#include "util-inl.h" +#include "v8.h" + #include <unicode/putil.h> #include <unicode/udata.h> +#include <unicode/uidna.h> #ifdef NODE_HAVE_SMALL_ICU /* 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[]; namespace node { +using v8::Context; +using v8::FunctionCallbackInfo; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Value; + bool flag_icu_data_dir = false; namespace i18n { @@ -64,7 +79,124 @@ bool InitializeICUDirectory(const char* icu_data_path) { } } +static int32_t ToUnicode(MaybeStackBuffer<char>* buf, + const char* input, + size_t length) { + UErrorCode status = U_ZERO_ERROR; + uint32_t options = UIDNA_DEFAULT; + options |= UIDNA_NONTRANSITIONAL_TO_UNICODE; + UIDNA* uidna = uidna_openUTS46(options, &status); + if (U_FAILURE(status)) + return -1; + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + + int32_t len = uidna_nameToUnicodeUTF8(uidna, + input, length, + **buf, buf->length(), + &info, + &status); + + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + buf->AllocateSufficientStorage(len); + len = uidna_nameToUnicodeUTF8(uidna, + input, length, + **buf, buf->length(), + &info, + &status); + } + + if (U_FAILURE(status)) + len = -1; + + uidna_close(uidna); + return len; +} + +static int32_t ToASCII(MaybeStackBuffer<char>* buf, + const char* input, + size_t length) { + UErrorCode status = U_ZERO_ERROR; + uint32_t options = UIDNA_DEFAULT; + options |= UIDNA_NONTRANSITIONAL_TO_ASCII; + UIDNA* uidna = uidna_openUTS46(options, &status); + if (U_FAILURE(status)) + return -1; + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + + int32_t len = uidna_nameToASCII_UTF8(uidna, + input, length, + **buf, buf->length(), + &info, + &status); + + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + buf->AllocateSufficientStorage(len); + len = uidna_nameToASCII_UTF8(uidna, + input, length, + **buf, buf->length(), + &info, + &status); + } + + if (U_FAILURE(status)) + len = -1; + + uidna_close(uidna); + return len; +} + +static void ToUnicode(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + CHECK_GE(args.Length(), 1); + CHECK(args[0]->IsString()); + Utf8Value val(env->isolate(), args[0]); + MaybeStackBuffer<char> buf; + int32_t len = ToUnicode(&buf, *val, val.length()); + + if (len < 0) { + return env->ThrowError("Cannot convert name to Unicode"); + } + + args.GetReturnValue().Set( + String::NewFromUtf8(env->isolate(), + *buf, + v8::NewStringType::kNormal, + len).ToLocalChecked()); +} + +static void ToASCII(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + CHECK_GE(args.Length(), 1); + CHECK(args[0]->IsString()); + Utf8Value val(env->isolate(), args[0]); + MaybeStackBuffer<char> buf; + int32_t len = ToASCII(&buf, *val, val.length()); + + if (len < 0) { + return env->ThrowError("Cannot convert name to ASCII"); + } + + args.GetReturnValue().Set( + String::NewFromUtf8(env->isolate(), + *buf, + v8::NewStringType::kNormal, + len).ToLocalChecked()); +} + +void Init(Local<Object> target, + Local<Value> unused, + Local<Context> context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + env->SetMethod(target, "toUnicode", ToUnicode); + env->SetMethod(target, "toASCII", ToASCII); +} + } // namespace i18n } // namespace node +NODE_MODULE_CONTEXT_AWARE_BUILTIN(icu, node::i18n::Init) + #endif // NODE_HAVE_I18N_SUPPORT |