• 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     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