1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "error_util.h"
17 #include "i18n_hilog.h"
18 #include "locale_info_addon.h"
19 #include "variable_convertor.h"
20 #include "simple_date_time_format_addon.h"
21
22 namespace OHOS {
23 namespace Global {
24 namespace I18n {
25 static thread_local napi_ref* g_SimpleDateTimeFormatConstructor = nullptr;
26 static const size_t SIZE_WITHOUR_LOCALE = 2;
27 static const size_t SIZE_WITH_LOCALE = 3;
28 static const std::string GET_TIME_NAME = "getTime";
29
SimpleDateTimeFormatAddon()30 SimpleDateTimeFormatAddon::SimpleDateTimeFormatAddon() {}
31
~SimpleDateTimeFormatAddon()32 SimpleDateTimeFormatAddon::~SimpleDateTimeFormatAddon() {}
33
Destructor(napi_env env,void * nativeObject,void * hint)34 void SimpleDateTimeFormatAddon::Destructor(napi_env env, void *nativeObject, void *hint)
35 {
36 if (!nativeObject) {
37 return;
38 }
39 delete reinterpret_cast<SimpleDateTimeFormatAddon *>(nativeObject);
40 nativeObject = nullptr;
41 }
42
InitSimpleDateTimeFormat(napi_env env,napi_value exports)43 napi_value SimpleDateTimeFormatAddon::InitSimpleDateTimeFormat(napi_env env, napi_value exports)
44 {
45 napi_property_descriptor properties[] = {
46 DECLARE_NAPI_FUNCTION("format", Format),
47 };
48
49 napi_value constructor = nullptr;
50 napi_status status = napi_define_class(env, "SimpleDateTimeFormat", NAPI_AUTO_LENGTH,
51 SimpleDateTimeFormatConstructor, nullptr, sizeof(properties) / sizeof(napi_property_descriptor),
52 properties, &constructor);
53 if (status != napi_ok) {
54 HILOG_ERROR_I18N("InitSimpleDateTimeFormat: Failed to define class SimpleDateTimeFormat at Init");
55 return nullptr;
56 }
57
58 g_SimpleDateTimeFormatConstructor = new (std::nothrow) napi_ref;
59 if (!g_SimpleDateTimeFormatConstructor) {
60 HILOG_ERROR_I18N("InitSimpleDateTimeFormat: Failed to create SimpleDateTimeFormat ref at init");
61 return nullptr;
62 }
63 status = napi_create_reference(env, constructor, 1, g_SimpleDateTimeFormatConstructor);
64 if (status != napi_ok) {
65 HILOG_ERROR_I18N(
66 "InitSimpleDateTimeFormat: Failed to create reference g_SimpleDateTimeFormatConstructor at init.");
67 return nullptr;
68 }
69
70 status = napi_set_named_property(env, exports, "SimpleDateTimeFormat", constructor);
71 if (status != napi_ok) {
72 HILOG_ERROR_I18N("InitSimpleDateTimeFormat: Set property failed.");
73 return nullptr;
74 }
75 return exports;
76 }
77
GetSimpleDateTimeFormatByPattern(napi_env env,napi_callback_info info)78 napi_value SimpleDateTimeFormatAddon::GetSimpleDateTimeFormatByPattern(napi_env env, napi_callback_info info)
79 {
80 size_t argc = 0;
81 std::vector<napi_value> parameters = GenerateParameter(env, info, true, argc);
82 if (argc == 0) {
83 HILOG_ERROR_I18N("GetSimpleDateTimeFormatByPattern: Generate parameter failed.");
84 return nullptr;
85 }
86 napi_value constructor = nullptr;
87 napi_status status = napi_get_reference_value(env, *g_SimpleDateTimeFormatConstructor, &constructor);
88 if (status != napi_ok) {
89 HILOG_ERROR_I18N("GetSimpleDateTimeFormatByPattern: Failed to create reference.");
90 return nullptr;
91 }
92 napi_value argv[SIZE_WITH_LOCALE] = { nullptr };
93 for (size_t i = 0; i < argc; i++) {
94 argv[i] = parameters[i];
95 }
96 napi_value result = nullptr;
97 status = napi_new_instance(env, constructor, argc, argv, &result);
98 if (status != napi_ok) {
99 HILOG_ERROR_I18N("GetSimpleDateTimeFormatByPattern: Create instance failed");
100 return nullptr;
101 }
102 return result;
103 }
104
GetSimpleDateTimeFormatBySkeleton(napi_env env,napi_callback_info info)105 napi_value SimpleDateTimeFormatAddon::GetSimpleDateTimeFormatBySkeleton(napi_env env, napi_callback_info info)
106 {
107 size_t argc = 0;
108 std::vector<napi_value> parameters = GenerateParameter(env, info, false, argc);
109 if (argc <= 1) {
110 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Generate parameter failed.");
111 return nullptr;
112 }
113 napi_value constructor = nullptr;
114 napi_status status = napi_get_reference_value(env, *g_SimpleDateTimeFormatConstructor, &constructor);
115 if (status != napi_ok) {
116 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Failed to create reference.");
117 return nullptr;
118 }
119 napi_value argv[SIZE_WITH_LOCALE] = { nullptr };
120 for (size_t i = 0; i < argc; i++) {
121 argv[i] = parameters[i];
122 }
123 napi_value result = nullptr;
124 status = napi_new_instance(env, constructor, argc, argv, &result);
125 if (status != napi_ok) {
126 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Create instance failed");
127 return nullptr;
128 }
129 return result;
130 }
131
Format(napi_env env,napi_callback_info info)132 napi_value SimpleDateTimeFormatAddon::Format(napi_env env, napi_callback_info info)
133 {
134 size_t argc = 1;
135 napi_value argv[1] = { 0 };
136 napi_value thisVar = nullptr;
137 void *data = nullptr;
138 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
139 if (status != napi_ok) {
140 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::Format: get cb info failed.");
141 return VariableConvertor::CreateString(env, "");
142 }
143 if (argc < 1) {
144 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "date", "", true);
145 return VariableConvertor::CreateString(env, "");
146 }
147 int64_t milliseconds = 0;
148 if (!GetDateTime(env, argv[0], milliseconds)) {
149 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::Format: get date time failed.");
150 return VariableConvertor::CreateString(env, "");
151 }
152
153 SimpleDateTimeFormatAddon* obj = nullptr;
154 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
155 if (status != napi_ok || !obj || !obj->simpleDateTimeFormat_) {
156 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: unwrap SimpleDateTimeFormatAddon failed.");
157 return VariableConvertor::CreateString(env, "");
158 }
159 std::string formatResult = obj->simpleDateTimeFormat_->Format(milliseconds);
160 if (formatResult.empty()) {
161 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: format result is empty.");
162 }
163 return VariableConvertor::CreateString(env, formatResult);
164 }
165
GenerateParameter(napi_env env,napi_callback_info info,bool isBestPattern,size_t & num)166 std::vector<napi_value> SimpleDateTimeFormatAddon::GenerateParameter(napi_env env, napi_callback_info info,
167 bool isBestPattern, size_t& num)
168 {
169 size_t argc = 2;
170 napi_value argv[2] = { nullptr };
171 napi_value thisVar = nullptr;
172 void *data = nullptr;
173 std::vector<napi_value> result;
174 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
175 if (status != napi_ok) {
176 HILOG_ERROR_I18N("GenerateParameter: Failed to get cb info.");
177 return result;
178 }
179 std::string type = isBestPattern ? "pattern" : "skeleton";
180 if (argc < 1) {
181 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, type, "", true);
182 return result;
183 }
184
185 napi_valuetype valueType = napi_valuetype::napi_undefined;
186 status = napi_typeof(env, argv[0], &valueType);
187 if (status != napi_ok) {
188 HILOG_ERROR_I18N("GenerateParameter: Failed to get type of argv[0].");
189 return result;
190 } else if (valueType != napi_valuetype::napi_string) {
191 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, type, "string", true);
192 return result;
193 }
194
195 napi_value flag;
196 status = napi_get_boolean(env, isBestPattern, &flag);
197 if (status != napi_ok) {
198 HILOG_ERROR_I18N("GenerateParameter: Create js boolean failed.");
199 return result;
200 }
201 result.emplace_back(flag);
202 for (size_t i = 0; i < argc; i++) {
203 result.emplace_back(argv[i]);
204 }
205 num = argc + 1;
206 return result;
207 }
208
SimpleDateTimeFormatConstructor(napi_env env,napi_callback_info info)209 napi_value SimpleDateTimeFormatAddon::SimpleDateTimeFormatConstructor(napi_env env, napi_callback_info info)
210 {
211 size_t argc = 3;
212 napi_value argv[3] = { nullptr };
213 napi_value thisVar = nullptr;
214 void *data = nullptr;
215 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
216 if (status != napi_ok || argc < SIZE_WITHOUR_LOCALE) {
217 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get cb info failed.");
218 return nullptr;
219 }
220 bool isBestPattern = false;
221 status = napi_get_value_bool(env, argv[0], &isBestPattern);
222 if (status != napi_ok) {
223 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get value argv[0] failed.");
224 return nullptr;
225 }
226
227 int32_t code = 0;
228 std::string skeleton = VariableConvertor::GetString(env, argv[1], code);
229 if (code != 0) {
230 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get argv[1] failed.");
231 return nullptr;
232 }
233
234 std::shared_ptr<LocaleInfo> localeInfo = (argc > SIZE_WITHOUR_LOCALE)?
235 VariableConvertor::ParseIntlLocale(env, argv[SIZE_WITH_LOCALE - 1]) : nullptr;
236
237 std::unique_ptr<SimpleDateTimeFormatAddon> obj = std::make_unique<SimpleDateTimeFormatAddon>();
238 if (obj == nullptr) {
239 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Cerate SimpleDateTimeFormatAddon failed.");
240 return nullptr;
241 }
242 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
243 SimpleDateTimeFormatAddon::Destructor, nullptr, nullptr);
244 if (status != napi_ok) {
245 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: wrap SimpleDateTimeFormatAddon failed");
246 return nullptr;
247 }
248 I18nErrorCode errCode = I18nErrorCode::SUCCESS;
249 obj->simpleDateTimeFormat_ = std::make_unique<SimpleDateTimeFormat>(skeleton, localeInfo, isBestPattern, errCode);
250 if (errCode == I18nErrorCode::INVALID_DATE_TIME_FORMAT_SKELETON) {
251 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "skeleton", "a valid date time format skeleton", true);
252 return nullptr;
253 } else if (errCode == I18nErrorCode::INVALID_DATE_TIME_FORMAT_PATTERN) {
254 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "pattern", "a valid date time format pattern", true);
255 return nullptr;
256 } else if (!obj->simpleDateTimeFormat_ || errCode != I18nErrorCode::SUCCESS) {
257 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Construct SimpleDateTimeFormat failed.");
258 return nullptr;
259 }
260 obj.release();
261 return thisVar;
262 }
263
GetDateTime(napi_env env,napi_value date,int64_t & milliseconds)264 bool SimpleDateTimeFormatAddon::GetDateTime(napi_env env, napi_value date, int64_t& milliseconds)
265 {
266 bool isDate = false;
267 napi_status status = napi_is_date(env, date, &isDate);
268 if (status != napi_ok) {
269 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon: Failed to call napi_is_date.");
270 return false;
271 } else if (!isDate) {
272 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "date", "Date", true);
273 return false;
274 }
275
276 napi_value funcGetTime = nullptr;
277 status = napi_get_named_property(env, date, GET_TIME_NAME.c_str(), &funcGetTime);
278 if (status != napi_ok || funcGetTime == nullptr) {
279 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Get named property failed.");
280 return false;
281 }
282
283 napi_value value = nullptr;
284 status = napi_call_function(env, date, funcGetTime, 0, nullptr, &value);
285 if (status != napi_ok || value == nullptr) {
286 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Call getTime failed.");
287 return false;
288 }
289
290 status = napi_get_value_int64(env, value, &milliseconds);
291 if (status != napi_ok) {
292 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Get milliseconds failed.");
293 return false;
294 }
295 return true;
296 }
297 } // namespace I18n
298 } // namespace Global
299 } // namespace OHOS