GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/node_i18n.cc Lines: 73 80 91.3 %
Date: 2016-07-23 Branches: 14 26 53.8 %

Line Exec Source
1
/*
2
 * notes: by srl295
3
 *  - When in NODE_HAVE_SMALL_ICU mode, ICU is linked against "stub" (null) data
4
 *     ( stubdata/libicudata.a ) containing nothing, no data, and it's also
5
 *    linked against a "small" data file which the SMALL_ICUDATA_ENTRY_POINT
6
 *    macro names. That's the "english+root" data.
7
 *
8
 *    If icu_data_path is non-null, the user has provided a path and we assume
9
 *    it goes somewhere useful. We set that path in ICU, and exit.
10
 *    If icu_data_path is null, they haven't set a path and we want the
11
 *    "english+root" data.  We call
12
 *       udata_setCommonData(SMALL_ICUDATA_ENTRY_POINT,...)
13
 *    to load up the english+root data.
14
 *
15
 *  - when NOT in NODE_HAVE_SMALL_ICU mode, ICU is linked directly with its full
16
 *    data. All of the variables and command line options for changing data at
17
 *    runtime are disabled, as they wouldn't fully override the internal data.
18
 *    See:  http://bugs.icu-project.org/trac/ticket/10924
19
 */
20
21
22
#include "node_i18n.h"
23
24
#if defined(NODE_HAVE_I18N_SUPPORT)
25
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
33
#include <unicode/putil.h>
34
#include <unicode/udata.h>
35
#include <unicode/uidna.h>
36
37
#ifdef NODE_HAVE_SMALL_ICU
38
/* if this is defined, we have a 'secondary' entry point.
39
   compare following to utypes.h defs for U_ICUDATA_ENTRY_POINT */
40
#define SMALL_ICUDATA_ENTRY_POINT \
41
  SMALL_DEF2(U_ICU_VERSION_MAJOR_NUM, U_LIB_SUFFIX_C_NAME)
42
#define SMALL_DEF2(major, suff) SMALL_DEF(major, suff)
43
#ifndef U_LIB_SUFFIX_C_NAME
44
#define SMALL_DEF(major, suff) icusmdt##major##_dat
45
#else
46
#define SMALL_DEF(major, suff) icusmdt##suff##major##_dat
47
#endif
48
49
extern "C" const char U_DATA_API SMALL_ICUDATA_ENTRY_POINT[];
50
#endif
51
52
namespace node {
53
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
61
bool flag_icu_data_dir = false;
62
63
namespace i18n {
64
65
1565
bool InitializeICUDirectory(const char* icu_data_path) {
66
1565
  if (icu_data_path != nullptr) {
67
    flag_icu_data_dir = true;
68
    u_setDataDirectory(icu_data_path);
69
    return true;  // no error
70
  } else {
71
1565
    UErrorCode status = U_ZERO_ERROR;
72
#ifdef NODE_HAVE_SMALL_ICU
73
    // install the 'small' data.
74
1565
    udata_setCommonData(&SMALL_ICUDATA_ENTRY_POINT, &status);
75
#else  // !NODE_HAVE_SMALL_ICU
76
    // no small data, so nothing to do.
77
#endif  // !NODE_HAVE_SMALL_ICU
78
1565
    return (status == U_ZERO_ERROR);
79
  }
80
}
81
82
45
static int32_t ToUnicode(MaybeStackBuffer<char>* buf,
83
                         const char* input,
84
                         size_t length) {
85
45
  UErrorCode status = U_ZERO_ERROR;
86
45
  uint32_t options = UIDNA_DEFAULT;
87
45
  options |= UIDNA_NONTRANSITIONAL_TO_UNICODE;
88
45
  UIDNA* uidna = uidna_openUTS46(options, &status);
89
45
  if (U_FAILURE(status))
90
    return -1;
91
45
  UIDNAInfo info = UIDNA_INFO_INITIALIZER;
92
93
45
  int32_t len = uidna_nameToUnicodeUTF8(uidna,
94
                                        input, length,
95
45
                                        **buf, buf->length(),
96
                                        &info,
97
45
                                        &status);
98
99
45
  if (status == U_BUFFER_OVERFLOW_ERROR) {
100
45
    status = U_ZERO_ERROR;
101
45
    buf->AllocateSufficientStorage(len);
102
45
    len = uidna_nameToUnicodeUTF8(uidna,
103
                                  input, length,
104
45
                                  **buf, buf->length(),
105
                                  &info,
106
45
                                  &status);
107
  }
108
109
45
  if (U_FAILURE(status))
110
    len = -1;
111
112
45
  uidna_close(uidna);
113
45
  return len;
114
}
115
116
1984
static int32_t ToASCII(MaybeStackBuffer<char>* buf,
117
                       const char* input,
118
                       size_t length) {
119
1984
  UErrorCode status = U_ZERO_ERROR;
120
1984
  uint32_t options = UIDNA_DEFAULT;
121
1984
  options |= UIDNA_NONTRANSITIONAL_TO_ASCII;
122
1984
  UIDNA* uidna = uidna_openUTS46(options, &status);
123
1984
  if (U_FAILURE(status))
124
    return -1;
125
1984
  UIDNAInfo info = UIDNA_INFO_INITIALIZER;
126
127
1984
  int32_t len = uidna_nameToASCII_UTF8(uidna,
128
                                       input, length,
129
1984
                                       **buf, buf->length(),
130
                                       &info,
131
1984
                                       &status);
132
133
1984
  if (status == U_BUFFER_OVERFLOW_ERROR) {
134
1654
    status = U_ZERO_ERROR;
135
1654
    buf->AllocateSufficientStorage(len);
136
1654
    len = uidna_nameToASCII_UTF8(uidna,
137
                                 input, length,
138
1654
                                 **buf, buf->length(),
139
                                 &info,
140
1654
                                 &status);
141
  }
142
143
1984
  if (U_FAILURE(status))
144
    len = -1;
145
146
1984
  uidna_close(uidna);
147
1984
  return len;
148
}
149
150
45
static void ToUnicode(const FunctionCallbackInfo<Value>& args) {
151
45
  Environment* env = Environment::GetCurrent(args);
152
45
  CHECK_GE(args.Length(), 1);
153
90
  CHECK(args[0]->IsString());
154
90
  Utf8Value val(env->isolate(), args[0]);
155
90
  MaybeStackBuffer<char> buf;
156
45
  int32_t len = ToUnicode(&buf, *val, val.length());
157
158
45
  if (len < 0) {
159
    return env->ThrowError("Cannot convert name to Unicode");
160
  }
161
162
90
  args.GetReturnValue().Set(
163
90
      String::NewFromUtf8(env->isolate(),
164
45
                          *buf,
165
                          v8::NewStringType::kNormal,
166
90
                          len).ToLocalChecked());
167
}
168
169
1984
static void ToASCII(const FunctionCallbackInfo<Value>& args) {
170
1984
  Environment* env = Environment::GetCurrent(args);
171
1984
  CHECK_GE(args.Length(), 1);
172
3968
  CHECK(args[0]->IsString());
173
3968
  Utf8Value val(env->isolate(), args[0]);
174
3968
  MaybeStackBuffer<char> buf;
175
1984
  int32_t len = ToASCII(&buf, *val, val.length());
176
177
1984
  if (len < 0) {
178
    return env->ThrowError("Cannot convert name to ASCII");
179
  }
180
181
3968
  args.GetReturnValue().Set(
182
3968
      String::NewFromUtf8(env->isolate(),
183
1984
                          *buf,
184
                          v8::NewStringType::kNormal,
185
3968
                          len).ToLocalChecked());
186
}
187
188
346
void Init(Local<Object> target,
189
          Local<Value> unused,
190
          Local<Context> context,
191
          void* priv) {
192
346
  Environment* env = Environment::GetCurrent(context);
193
346
  env->SetMethod(target, "toUnicode", ToUnicode);
194
346
  env->SetMethod(target, "toASCII", ToASCII);
195
346
}
196
197
}  // namespace i18n
198
}  // namespace node
199
200
1569
NODE_MODULE_CONTEXT_AWARE_BUILTIN(icu, node::i18n::Init)
201
202
#endif  // NODE_HAVE_I18N_SUPPORT