• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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