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 if (g_SimpleDateTimeFormatConstructor == nullptr) {
88 HILOG_ERROR_I18N("Failed to create g_SimpleDateTimeFormatConstructor");
89 return nullptr;
90 }
91 napi_status status = napi_get_reference_value(env, *g_SimpleDateTimeFormatConstructor, &constructor);
92 if (status != napi_ok) {
93 HILOG_ERROR_I18N("GetSimpleDateTimeFormatByPattern: Failed to create reference.");
94 return nullptr;
95 }
96 napi_value argv[SIZE_WITH_LOCALE] = { nullptr };
97 for (size_t i = 0; i < argc; i++) {
98 argv[i] = parameters[i];
99 }
100 napi_value result = nullptr;
101 status = napi_new_instance(env, constructor, argc, argv, &result);
102 if (status != napi_ok) {
103 HILOG_ERROR_I18N("GetSimpleDateTimeFormatByPattern: Create instance failed");
104 return nullptr;
105 }
106 return result;
107 }
108
GetSimpleDateTimeFormatBySkeleton(napi_env env,napi_callback_info info)109 napi_value SimpleDateTimeFormatAddon::GetSimpleDateTimeFormatBySkeleton(napi_env env, napi_callback_info info)
110 {
111 size_t argc = 0;
112 std::vector<napi_value> parameters = GenerateParameter(env, info, false, argc);
113 if (argc <= 1) {
114 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Generate parameter failed.");
115 return nullptr;
116 }
117 napi_value constructor = nullptr;
118 napi_status status = napi_get_reference_value(env, *g_SimpleDateTimeFormatConstructor, &constructor);
119 if (status != napi_ok) {
120 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Failed to create reference.");
121 return nullptr;
122 }
123 napi_value argv[SIZE_WITH_LOCALE] = { nullptr };
124 for (size_t i = 0; i < argc; i++) {
125 argv[i] = parameters[i];
126 }
127 napi_value result = nullptr;
128 status = napi_new_instance(env, constructor, argc, argv, &result);
129 if (status != napi_ok) {
130 HILOG_ERROR_I18N("GetSimpleDateTimeFormatBySkeleton: Create instance failed");
131 return nullptr;
132 }
133 return result;
134 }
135
Format(napi_env env,napi_callback_info info)136 napi_value SimpleDateTimeFormatAddon::Format(napi_env env, napi_callback_info info)
137 {
138 size_t argc = 1;
139 napi_value argv[1] = { 0 };
140 napi_value thisVar = nullptr;
141 void *data = nullptr;
142 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
143 if (status != napi_ok) {
144 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::Format: get cb info failed.");
145 return VariableConvertor::CreateString(env, "");
146 }
147 if (argc < 1) {
148 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "date", "", true);
149 return VariableConvertor::CreateString(env, "");
150 }
151 int64_t milliseconds = 0;
152 if (!GetDateTime(env, argv[0], milliseconds)) {
153 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::Format: get date time failed.");
154 return VariableConvertor::CreateString(env, "");
155 }
156
157 SimpleDateTimeFormatAddon* obj = nullptr;
158 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
159 if (status != napi_ok || !obj || !obj->simpleDateTimeFormat_) {
160 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: unwrap SimpleDateTimeFormatAddon failed.");
161 return VariableConvertor::CreateString(env, "");
162 }
163 std::string formatResult = obj->simpleDateTimeFormat_->Format(milliseconds);
164 if (formatResult.empty()) {
165 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: format result is empty.");
166 }
167 return VariableConvertor::CreateString(env, formatResult);
168 }
169
GenerateParameter(napi_env env,napi_callback_info info,bool isBestPattern,size_t & num)170 std::vector<napi_value> SimpleDateTimeFormatAddon::GenerateParameter(napi_env env, napi_callback_info info,
171 bool isBestPattern, size_t& num)
172 {
173 size_t argc = 2;
174 napi_value argv[2] = { nullptr };
175 napi_value thisVar = nullptr;
176 void *data = nullptr;
177 std::vector<napi_value> result;
178 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
179 if (status != napi_ok) {
180 HILOG_ERROR_I18N("GenerateParameter: Failed to get cb info.");
181 return result;
182 }
183 std::string type = isBestPattern ? "pattern" : "skeleton";
184 if (argc < 1) {
185 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, type, "", true);
186 return result;
187 }
188
189 napi_valuetype valueType = napi_valuetype::napi_undefined;
190 status = napi_typeof(env, argv[0], &valueType);
191 if (status != napi_ok) {
192 HILOG_ERROR_I18N("GenerateParameter: Failed to get type of argv[0].");
193 return result;
194 } else if (valueType != napi_valuetype::napi_string) {
195 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, type, "string", true);
196 return result;
197 }
198
199 napi_value flag;
200 status = napi_get_boolean(env, isBestPattern, &flag);
201 if (status != napi_ok) {
202 HILOG_ERROR_I18N("GenerateParameter: Create js boolean failed.");
203 return result;
204 }
205 result.emplace_back(flag);
206 for (size_t i = 0; i < argc; i++) {
207 result.emplace_back(argv[i]);
208 }
209 num = argc + 1;
210 return result;
211 }
212
SimpleDateTimeFormatConstructor(napi_env env,napi_callback_info info)213 napi_value SimpleDateTimeFormatAddon::SimpleDateTimeFormatConstructor(napi_env env, napi_callback_info info)
214 {
215 size_t argc = 3;
216 napi_value argv[3] = { nullptr };
217 napi_value thisVar = nullptr;
218 void *data = nullptr;
219 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
220 if (status != napi_ok || argc < SIZE_WITHOUR_LOCALE) {
221 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get cb info failed.");
222 return nullptr;
223 }
224 bool isBestPattern = false;
225 status = napi_get_value_bool(env, argv[0], &isBestPattern);
226 if (status != napi_ok) {
227 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get value argv[0] failed.");
228 return nullptr;
229 }
230
231 int32_t code = 0;
232 std::string skeleton = VariableConvertor::GetString(env, argv[1], code);
233 if (code != 0) {
234 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Get argv[1] failed.");
235 return nullptr;
236 }
237
238 std::unique_ptr<SimpleDateTimeFormatAddon> obj = std::make_unique<SimpleDateTimeFormatAddon>();
239 if (obj == nullptr) {
240 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Cerate SimpleDateTimeFormatAddon failed.");
241 return nullptr;
242 }
243 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
244 SimpleDateTimeFormatAddon::Destructor, nullptr, nullptr);
245 if (status != napi_ok) {
246 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: wrap SimpleDateTimeFormatAddon failed");
247 return nullptr;
248 }
249 I18nErrorCode errCode = I18nErrorCode::SUCCESS;
250 napi_value locale = (argc > SIZE_WITHOUR_LOCALE) ? argv[SIZE_WITH_LOCALE - 1] : nullptr;
251 obj->simpleDateTimeFormat_ =
252 SimpleDateTimeFormatAddon::InitSimpleDateTimeFormatContext(env, locale, skeleton, isBestPattern, errCode);
253 if (errCode == I18nErrorCode::INVALID_DATE_TIME_FORMAT_SKELETON) {
254 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "skeleton", "a valid date time format skeleton", true);
255 return nullptr;
256 } else if (errCode == I18nErrorCode::INVALID_DATE_TIME_FORMAT_PATTERN) {
257 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "pattern", "a valid date time format pattern", true);
258 return nullptr;
259 } else if (!obj->simpleDateTimeFormat_ || errCode != I18nErrorCode::SUCCESS) {
260 HILOG_ERROR_I18N("SimpleDateTimeFormatConstructor: Construct SimpleDateTimeFormat failed.");
261 return nullptr;
262 }
263 obj.release();
264 return thisVar;
265 }
266
InitSimpleDateTimeFormatContext(napi_env env,napi_value locale,const std::string & skeleton,bool isBestPattern,I18nErrorCode & errCode)267 std::unique_ptr<SimpleDateTimeFormat> SimpleDateTimeFormatAddon::InitSimpleDateTimeFormatContext(napi_env env,
268 napi_value locale, const std::string& skeleton, bool isBestPattern, I18nErrorCode& errCode)
269 {
270 if (locale == nullptr) {
271 std::shared_ptr<LocaleInfo> localeInfo = nullptr;
272 return std::make_unique<SimpleDateTimeFormat>(skeleton, localeInfo, isBestPattern, errCode);
273 }
274
275 if (VariableConvertor::GetLocaleType(env, locale) == LocaleType::BUILTINS_LOCALE) {
276 std::string localeTag = VariableConvertor::ParseBuiltinsLocale(env, locale);
277 return std::make_unique<SimpleDateTimeFormat>(skeleton, localeTag, isBestPattern, errCode);
278 } else if (VariableConvertor::GetLocaleType(env, locale) == LocaleType::LOCALE_INFO) {
279 std::shared_ptr<LocaleInfo> localeInfo = VariableConvertor::ParseLocaleInfo(env, locale);
280 return std::make_unique<SimpleDateTimeFormat>(skeleton, localeInfo, isBestPattern, errCode);
281 }
282 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::InitSimpleDateTimeFormatContext: Init context failed.");
283 return nullptr;
284 }
285
GetDateTime(napi_env env,napi_value date,int64_t & milliseconds)286 bool SimpleDateTimeFormatAddon::GetDateTime(napi_env env, napi_value date, int64_t& milliseconds)
287 {
288 bool isDate = false;
289 napi_status status = napi_is_date(env, date, &isDate);
290 if (status != napi_ok) {
291 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon: Failed to call napi_is_date.");
292 return false;
293 } else if (!isDate) {
294 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "date", "Date", true);
295 return false;
296 }
297
298 napi_value funcGetTime = nullptr;
299 status = napi_get_named_property(env, date, GET_TIME_NAME.c_str(), &funcGetTime);
300 if (status != napi_ok || funcGetTime == nullptr) {
301 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Get named property failed.");
302 return false;
303 }
304
305 napi_value value = nullptr;
306 status = napi_call_function(env, date, funcGetTime, 0, nullptr, &value);
307 if (status != napi_ok || value == nullptr) {
308 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Call getTime failed.");
309 return false;
310 }
311
312 status = napi_get_value_int64(env, value, &milliseconds);
313 if (status != napi_ok) {
314 HILOG_ERROR_I18N("SimpleDateTimeFormatAddon::GetDateTime: Get milliseconds failed.");
315 return false;
316 }
317 return true;
318 }
319 } // namespace I18n
320 } // namespace Global
321 } // namespace OHOS