1 /*
2 * Copyright (c) 2021-2023 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 "napi_utils.h"
17
18 #include <cstddef>
19
20 #include "js_native_api_types.h"
21
22 #include "base/utils/string_utils.h"
23 #include "core/animation/curve.h"
24 #include "core/common/resource/resource_manager.h"
25 #include "core/common/resource/resource_object.h"
26 #include "frameworks/bridge/common/utils/utils.h"
27
28 namespace OHOS::Ace::Napi {
29 using namespace OHOS::Ace;
30 namespace {
31
32 const std::regex RESOURCE_APP_STRING_PLACEHOLDER(R"(\%((\d+)(\$)){0,1}([dsf]))", std::regex::icase);
33 constexpr int32_t NAPI_BUF_LENGTH = 256;
34 constexpr int32_t UNKNOWN_RESOURCE_ID = -1;
35 constexpr char BUNDLE_NAME[] = "bundleName";
36 std::vector<std::string> RESOURCE_HEADS = { "app", "sys" };
37 } // namespace
38
39 static const std::unordered_map<int32_t, std::string> ERROR_CODE_TO_MSG {
40 { ERROR_CODE_PERMISSION_DENIED, "Permission denied. " },
41 { ERROR_CODE_PARAM_INVALID, "Parameter error. " },
42 { ERROR_CODE_SYSTEMCAP_ERROR, "Capability not supported. " },
43 { ERROR_CODE_INTERNAL_ERROR, "Internal error. " },
44 { ERROR_CODE_URI_ERROR, "Uri error. " },
45 { ERROR_CODE_PAGE_STACK_FULL, "Page stack error. " },
46 { ERROR_CODE_URI_ERROR_LITE, "Uri error. " },
47 { ERROR_CODE_DIALOG_CONTENT_ERROR, "Dialog content error. " },
48 { ERROR_CODE_DIALOG_CONTENT_ALREADY_EXIST, "Dialog content already exist. " },
49 { ERROR_CODE_DIALOG_CONTENT_NOT_FOUND, "Dialog content not found. " },
50 { ERROR_CODE_TOAST_NOT_FOUND, "Toast not found. " }
51 };
52
NapiThrow(napi_env env,const std::string & message,int32_t errCode)53 void NapiThrow(napi_env env, const std::string& message, int32_t errCode)
54 {
55 napi_value code = nullptr;
56 std::string strCode = std::to_string(errCode);
57 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
58
59 napi_value msg = nullptr;
60 auto iter = ERROR_CODE_TO_MSG.find(errCode);
61 std::string strMsg = (iter != ERROR_CODE_TO_MSG.end() ? iter->second : "") + message;
62 LOGE("napi throw errCode %d strMsg %s", errCode, strMsg.c_str());
63 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
64
65 napi_value error = nullptr;
66 napi_create_error(env, code, msg, &error);
67 napi_throw(env, error);
68 }
69
ReplaceHolder(std::string & originStr,const std::vector<std::string> & params,uint32_t containCount)70 void ReplaceHolder(std::string& originStr, const std::vector<std::string>& params, uint32_t containCount)
71 {
72 auto size = static_cast<uint32_t>(params.size());
73 if (containCount == size) {
74 return;
75 }
76 std::string::const_iterator start = originStr.begin();
77 std::string::const_iterator end = originStr.end();
78 std::smatch matches;
79 bool shortHolderType = false;
80 bool firstMatch = true;
81 uint32_t searchTime = 0;
82 while (std::regex_search(start, end, matches, RESOURCE_APP_STRING_PLACEHOLDER)) {
83 std::string pos = matches[2];
84 std::string type = matches[4];
85 if (firstMatch) {
86 firstMatch = false;
87 shortHolderType = pos.length() == 0;
88 } else {
89 if (static_cast<uint32_t>(shortHolderType) ^ ((uint32_t)(pos.length() == 0))) {
90 LOGE("wrong place holder,stop parse string");
91 return;
92 }
93 }
94
95 std::string replaceContentStr;
96 std::string::size_type index = 0;
97 if (shortHolderType) {
98 index = static_cast<std::string::size_type>(searchTime + containCount);
99 } else {
100 int32_t indexTmp = StringUtils::StringToInt(pos) + static_cast<int32_t>(containCount) - 1;
101 if (indexTmp >= 0) {
102 index = static_cast<std::string::size_type>(indexTmp);
103 } else {
104 LOGE("indexTmp err:%{public}d", indexTmp);
105 }
106 }
107 if (static_cast<uint32_t>(index) < size) {
108 replaceContentStr = params[index];
109 } else {
110 LOGE("index = %{public}d size = %{public}d", static_cast<uint32_t>(index), size);
111 }
112 originStr.replace(matches[0].first - originStr.begin(), matches[0].length(), replaceContentStr);
113 start = originStr.begin() + matches.prefix().length() + replaceContentStr.length();
114 end = originStr.end();
115 searchTime++;
116 }
117 }
118
GetParamLen(napi_env env,napi_value param)119 size_t GetParamLen(napi_env env, napi_value param)
120 {
121 size_t buffSize = 0;
122 napi_status status = napi_get_value_string_utf8(env, param, nullptr, 0, &buffSize);
123 if (status != napi_ok || buffSize == 0) {
124 return 0;
125 }
126 return buffSize;
127 }
128
NapiStringToString(napi_env env,napi_value value,std::string & retStr)129 bool NapiStringToString(napi_env env, napi_value value, std::string& retStr)
130 {
131 size_t ret = 0;
132 napi_valuetype valueType = napi_undefined;
133 napi_typeof(env, value, &valueType);
134 if (valueType != napi_string) {
135 return false;
136 }
137 if (GetParamLen(env, value) == 0) {
138 return false;
139 }
140 size_t valueLen = GetParamLen(env, value) + 1;
141 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(valueLen);
142 napi_get_value_string_utf8(env, value, buffer.get(), valueLen, &ret);
143 retStr = buffer.get();
144 return true;
145 }
146
GetNapiString(napi_env env,napi_value value,std::string & retStr,napi_valuetype & valueType)147 bool GetNapiString(napi_env env, napi_value value, std::string& retStr, napi_valuetype& valueType)
148 {
149 if (NapiStringToString(env, value, retStr)) {
150 return true;
151 }
152 napi_typeof(env, value, &valueType);
153 if (valueType == napi_object) {
154 ResourceInfo recv;
155 if (ParseResourceParam(env, value, recv)) {
156 ParseString(recv, retStr);
157 return true;
158 }
159 }
160 return false;
161 }
162
GetThemeConstants(const std::optional<std::string> & bundleName=std::nullopt,const std::optional<std::string> & moduleName=std::nullopt)163 RefPtr<ThemeConstants> GetThemeConstants(const std::optional<std::string>& bundleName = std::nullopt,
164 const std::optional<std::string>& moduleName = std::nullopt)
165 {
166 auto container = Container::Current();
167 if (!container) {
168 LOGW("container is null");
169 return nullptr;
170 }
171 auto pipelineContext = container->GetPipelineContext();
172 if (!pipelineContext) {
173 LOGE("pipelineContext is null!");
174 return nullptr;
175 }
176 auto themeManager = pipelineContext->GetThemeManager();
177 if (!themeManager) {
178 LOGE("themeManager is null!");
179 return nullptr;
180 }
181 if (bundleName.has_value() && moduleName.has_value()) {
182 return themeManager->GetThemeConstants(bundleName.value_or(""), moduleName.value_or(""));
183 }
184 return themeManager->GetThemeConstants();
185 }
186
CreateResourceWrapper(const ResourceInfo & info)187 RefPtr<ResourceWrapper> CreateResourceWrapper(const ResourceInfo& info)
188 {
189 auto bundleName = info.bundleName;
190 auto moduleName = info.moduleName;
191
192 RefPtr<ResourceAdapter> resourceAdapter = nullptr;
193 RefPtr<ThemeConstants> themeConstants = nullptr;
194 if (SystemProperties::GetResourceDecoupling()) {
195 if (bundleName.has_value() && moduleName.has_value()) {
196 auto resourceObject = AceType::MakeRefPtr<ResourceObject>(bundleName.value_or(""), moduleName.value_or(""));
197 resourceAdapter = ResourceManager::GetInstance().GetOrCreateResourceAdapter(resourceObject);
198 } else {
199 resourceAdapter = ResourceManager::GetInstance().GetResourceAdapter();
200 }
201 if (!resourceAdapter) {
202 return nullptr;
203 }
204 } else {
205 themeConstants = GetThemeConstants(info.bundleName, info.moduleName);
206 if (!themeConstants) {
207 return nullptr;
208 }
209 }
210 auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
211 return resourceWrapper;
212 }
213
CreateNapiString(napi_env env,const std::string & rawStr)214 napi_value CreateNapiString(napi_env env, const std::string& rawStr)
215 {
216 napi_value retVal = nullptr;
217 napi_create_string_utf8(env, rawStr.c_str(), rawStr.length(), &retVal);
218 return retVal;
219 }
220
ConvertResourceType(const std::string & typeName,ResourceType & resType)221 bool ConvertResourceType(const std::string& typeName, ResourceType& resType)
222 {
223 static const std::unordered_map<std::string, ResourceType> resTypeMap {
224 { "color", ResourceType::COLOR },
225 { "media", ResourceType::MEDIA },
226 { "float", ResourceType::FLOAT },
227 { "string", ResourceType::STRING },
228 { "plural", ResourceType::PLURAL },
229 { "pattern", ResourceType::PATTERN },
230 { "boolean", ResourceType::BOOLEAN },
231 { "integer", ResourceType::INTEGER },
232 { "strarray", ResourceType::STRARRAY },
233 { "intarray", ResourceType::INTARRAY },
234 };
235 auto it = resTypeMap.find(typeName);
236 if (it == resTypeMap.end()) {
237 return false;
238 }
239 resType = it->second;
240 return true;
241 }
242
ParseDollarResource(napi_env env,napi_value value,ResourceType & resType,std::string & resName,std::string & moduleName)243 bool ParseDollarResource(
244 napi_env env, napi_value value, ResourceType& resType, std::string& resName, std::string& moduleName)
245 {
246 napi_valuetype valueType = napi_undefined;
247 napi_typeof(env, value, &valueType);
248 if (valueType != napi_string) {
249 return false;
250 }
251 std::string resPath;
252 if (!GetNapiString(env, value, resPath, valueType)) {
253 return false;
254 }
255 std::vector<std::string> tokens;
256 StringUtils::StringSplitter(resPath, '.', tokens);
257 // $r format like app.xxx.xxx, has 3 paragraph
258 if (static_cast<int32_t>(tokens.size()) != 3) {
259 return false;
260 }
261 std::string maybeModuleName = tokens[0];
262 // [*] or app/hsp at least has 3 chars
263 if (maybeModuleName.size() < 3) {
264 return false;
265 }
266 char begin = *maybeModuleName.begin();
267 char end = maybeModuleName.at(maybeModuleName.size() - 1);
268 bool headCheckPass = false;
269 if (begin == '[' && end == ']') {
270 // moduleName not include 2 brackets
271 moduleName = maybeModuleName.substr(1, maybeModuleName.size() - 2);
272 headCheckPass = true;
273 }
274 if (std::find(RESOURCE_HEADS.begin(), RESOURCE_HEADS.end(), tokens[0]) == RESOURCE_HEADS.end() && !headCheckPass) {
275 return false;
276 }
277 if (!ConvertResourceType(tokens[1], resType)) {
278 return false;
279 }
280 resName = resPath;
281 return true;
282 }
283
PreFixEmptyBundleName(napi_env env,napi_value value)284 void PreFixEmptyBundleName(napi_env env, napi_value value)
285 {
286 napi_value bundleNameNApi = nullptr;
287 if (napi_get_named_property(env, value, BUNDLE_NAME, &bundleNameNApi) != napi_ok) {
288 return;
289 }
290 std::string bundleName;
291 NapiStringToString(env, bundleNameNApi, bundleName);
292 if (bundleName.empty()) {
293 auto container = Container::CurrentSafely();
294 CHECK_NULL_VOID(container);
295 bundleName = container->GetBundleName();
296 bundleNameNApi = CreateNapiString(env, bundleName);
297 napi_set_named_property(env, value, BUNDLE_NAME, bundleNameNApi);
298 }
299 }
300
CheckResourceStruct(napi_env env,napi_value value)301 ResourceStruct CheckResourceStruct(napi_env env, napi_value value)
302 {
303 napi_value idNApi = nullptr;
304 napi_valuetype valueType = napi_undefined;
305 napi_typeof(env, value, &valueType);
306 if (valueType != napi_object) {
307 return ResourceStruct::CONSTANT;
308 }
309 if (napi_get_named_property(env, value, "id", &idNApi) != napi_ok) {
310 return ResourceStruct::CONSTANT;
311 }
312 napi_typeof(env, idNApi, &valueType);
313 if (valueType == napi_string) {
314 return ResourceStruct::DYNAMIC_V1;
315 }
316 if (valueType == napi_number) {
317 int32_t id = 0;
318 napi_get_value_int32(env, idNApi, &id);
319 if (id == UNKNOWN_RESOURCE_ID) {
320 return ResourceStruct::DYNAMIC_V2;
321 }
322 }
323 return ResourceStruct::CONSTANT;
324 }
325
CompleteResourceParam(napi_env env,napi_value value)326 void CompleteResourceParam(napi_env env, napi_value value)
327 {
328 PreFixEmptyBundleName(env, value);
329 ResourceStruct resourceStruct = CheckResourceStruct(env, value);
330 switch (resourceStruct) {
331 case ResourceStruct::CONSTANT:
332 return;
333 case ResourceStruct::DYNAMIC_V1:
334 CompleteResourceParamV1(env, value);
335 return;
336 case ResourceStruct::DYNAMIC_V2:
337 CompleteResourceParamV2(env, value);
338 return;
339 default:
340 return;
341 }
342 }
343
CompleteResourceParamV1(napi_env env,napi_value value)344 void CompleteResourceParamV1(napi_env env, napi_value value)
345 {
346 napi_value idNApi = nullptr;
347 napi_valuetype valueType = napi_undefined;
348 napi_typeof(env, value, &valueType);
349 if (valueType != napi_object) {
350 return;
351 }
352 if (napi_get_named_property(env, value, "id", &idNApi) != napi_ok) {
353 return;
354 }
355 std::string resName;
356 std::string moduleName;
357 ResourceType resType;
358 if (!ParseDollarResource(env, idNApi, resType, resName, moduleName)) {
359 return;
360 }
361 bool hasProperty = false;
362 napi_value typeIdNApi = nullptr;
363 napi_value resourceIdNApi = nullptr;
364 napi_value typeKeyNApi = CreateNapiString(env, "type");
365 napi_value defaultNameNApi = CreateNapiString(env, "");
366 napi_value bundleNameKeyNApi = CreateNapiString(env, "bundleName");
367 napi_value moduleNameKeyNApi = CreateNapiString(env, "moduleName");
368 napi_create_int32(env, UNKNOWN_RESOURCE_ID, &resourceIdNApi);
369 napi_create_int32(env, static_cast<uint32_t>(resType), &typeIdNApi);
370 ModifyResourceParam(env, value, resType, resName);
371 napi_set_property(env, value, typeKeyNApi, typeIdNApi);
372 napi_set_property(env, value, CreateNapiString(env, "id"), resourceIdNApi);
373 napi_has_property(env, value, bundleNameKeyNApi, &hasProperty);
374 if (!hasProperty) {
375 napi_set_property(env, value, bundleNameKeyNApi, defaultNameNApi);
376 }
377 napi_has_property(env, value, moduleNameKeyNApi, &hasProperty);
378 if (!hasProperty) {
379 napi_set_property(env, value, moduleNameKeyNApi, defaultNameNApi);
380 }
381 }
382
CompleteResourceParamV2(napi_env env,napi_value value)383 void CompleteResourceParamV2(napi_env env, napi_value value)
384 {
385 napi_value paramsNApi = nullptr;
386 if (napi_get_named_property(env, value, "params", ¶msNApi) != napi_ok) {
387 return;
388 }
389 bool isArray = false;
390 napi_is_array(env, paramsNApi, &isArray);
391 if (!isArray) {
392 return;
393 }
394 uint32_t paramCount = 0;
395 napi_get_array_length(env, paramsNApi, ¶mCount);
396 if (paramCount <= 0) {
397 return;
398 }
399 napi_value resNameNApi = nullptr;
400 napi_get_element(env, paramsNApi, 0, &resNameNApi);
401 std::string resName;
402 std::string moduleName;
403 ResourceType resType;
404 if (!ParseDollarResource(env, resNameNApi, resType, resName, moduleName)) {
405 return;
406 }
407 napi_value typeIdNApi = nullptr;
408 napi_value typeKeyNApi = CreateNapiString(env, "type");
409 napi_create_int32(env, static_cast<uint32_t>(resType), &typeIdNApi);
410 napi_set_property(env, value, typeKeyNApi, typeIdNApi);
411 if (!moduleName.empty()) {
412 napi_value moduleNameNApi = CreateNapiString(env, moduleName);
413 napi_value moduleNameKeyNApi = CreateNapiString(env, "moduleName");
414 napi_set_property(env, value, moduleNameKeyNApi, moduleNameNApi);
415 }
416 }
417
ModifyResourceParam(napi_env env,napi_value value,const ResourceType & resType,const std::string & resName)418 void ModifyResourceParam(napi_env env, napi_value value, const ResourceType& resType, const std::string& resName)
419 {
420 // raw input : {"id":"app.xxx.xxx","params":[],"moduleName":"xxx","bundleName":"xxx"}
421 // modified output : {"id":-1, "params":["app.xxx.xxx"],"type":xxxx,"moduleName":"xxx","bundleName":"xxx"}
422 napi_value paramsNApi = nullptr;
423 napi_get_named_property(env, value, "params", ¶msNApi);
424 bool isArray = false;
425 if (napi_is_array(env, paramsNApi, &isArray) != napi_ok) {
426 return;
427 }
428 if (!isArray) {
429 return;
430 }
431 uint32_t paramCount = 0;
432 bool hasProperty = false;
433 napi_get_array_length(env, paramsNApi, ¶mCount);
434 napi_value typeKeyNApi = CreateNapiString(env, "type");
435 napi_value resNameNApi = CreateNapiString(env, resName);
436 if (resType == ResourceType::PLURAL || resType == ResourceType::STRING) {
437 std::vector<napi_value> tmpParams;
438 for (uint32_t i = 0; i < paramCount; i++) {
439 napi_value param = nullptr;
440 napi_get_element(env, paramsNApi, i, ¶m);
441 tmpParams.insert(tmpParams.end(), param);
442 }
443 napi_set_element(env, paramsNApi, 0, resNameNApi);
444 uint32_t paramIndex = 1;
445 napi_has_property(env, value, typeKeyNApi, &hasProperty);
446 if (hasProperty) {
447 napi_value firstParam = nullptr;
448 napi_get_property(env, value, typeKeyNApi, &firstParam);
449 napi_set_element(env, paramsNApi, paramIndex, firstParam);
450 paramIndex++;
451 }
452 for (auto tmpParam : tmpParams) {
453 napi_set_element(env, paramsNApi, paramIndex, tmpParam);
454 paramIndex++;
455 }
456 } else {
457 napi_set_element(env, paramsNApi, 0, resNameNApi);
458 }
459 }
460
ParseCurveInfo(const std::string & curveString,std::string & curveTypeString,std::vector<float> & curveValue)461 void ParseCurveInfo(const std::string& curveString, std::string& curveTypeString, std::vector<float>& curveValue)
462 {
463 if (curveString.back() != ')') {
464 return;
465 }
466 std::string::size_type leftEmbracePosition = curveString.find_last_of('(');
467 if (leftEmbracePosition == std::string::npos) {
468 return;
469 }
470 curveTypeString = curveString.substr(0, leftEmbracePosition);
471 auto params = curveString.substr(leftEmbracePosition + 1, curveString.length() - leftEmbracePosition - 2);
472 if (curveTypeString.empty() || params.empty()) {
473 return;
474 }
475 std::vector<std::string> paramsVector;
476 StringUtils::StringSplitter(params, ',', paramsVector);
477 for (auto& param : paramsVector) {
478 Framework::RemoveHeadTailSpace(param);
479 if (param == "true" || param == "start") {
480 param = "1.000000";
481 }
482 if (param == "false" || param == "end") {
483 param = "0.000000";
484 }
485 errno = 0;
486 char* end = nullptr;
487 float value = strtof(param.c_str(), &end);
488 if (end == param.c_str() || errno == ERANGE) {
489 LOGW("%{public}s can not be converted to float or is out of range.", param.c_str());
490 }
491 curveValue.emplace_back(value);
492 }
493 }
494
ParseCurve(napi_env env,napi_value value,std::string & curveTypeString,std::vector<float> & curveValue)495 napi_value ParseCurve(napi_env env, napi_value value, std::string& curveTypeString, std::vector<float>& curveValue)
496 {
497 CHECK_NULL_RETURN(value, nullptr);
498 napi_valuetype valueType = napi_undefined;
499 napi_typeof(env, value, &valueType);
500 NAPI_ASSERT(env, valueType == napi_object || valueType == napi_string, "The type of curve is incorrect");
501 if (valueType == napi_object) {
502 napi_value curveObjectNApi = nullptr;
503 napi_get_named_property(env, value, "__curveString", &curveObjectNApi);
504 value = curveObjectNApi;
505 }
506
507 size_t paramLen = 0;
508 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, ¶mLen);
509 NAPI_ASSERT(env, paramLen > 0 && paramLen < NAPI_BUF_LENGTH && status == napi_ok, "paramLen error");
510 char params[NAPI_BUF_LENGTH] = { 0 };
511 status = napi_get_value_string_utf8(env, value, params, paramLen + 1, ¶mLen);
512 NAPI_ASSERT(env, status == napi_ok, "Parse curve failed");
513
514 RefPtr<Curve> curve;
515 const std::string domAnimationDefaultCurveString = "ease-in-out";
516 if (params[0] == '\0') {
517 curve = Framework::CreateCurve(domAnimationDefaultCurveString);
518 } else {
519 curve = Framework::CreateCurve(params);
520 }
521 std::string curveString = curve->ToString();
522 ParseCurveInfo(curveString, curveTypeString, curveValue);
523 return nullptr;
524 }
525
GetValueType(napi_env env,napi_value value)526 napi_valuetype GetValueType(napi_env env, napi_value value)
527 {
528 if (value == nullptr) {
529 return napi_undefined;
530 }
531
532 napi_valuetype valueType = napi_undefined;
533 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
534 return valueType;
535 }
536
GetStringFromValueUtf8(napi_env env,napi_value value)537 std::optional<std::string> GetStringFromValueUtf8(napi_env env, napi_value value)
538 {
539 static constexpr size_t maxLength = 2048;
540 if (GetValueType(env, value) != napi_string) {
541 return std::nullopt;
542 }
543
544 size_t paramLen = 0;
545 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, ¶mLen);
546 if (paramLen == 0 || paramLen > maxLength || status != napi_ok) {
547 return std::nullopt;
548 }
549 char params[maxLength] = { 0 };
550 status = napi_get_value_string_utf8(env, value, params, paramLen + 1, ¶mLen);
551 if (status != napi_ok) {
552 return std::nullopt;
553 }
554 return params;
555 }
556
GetIntProperty(napi_env env,napi_value value,const std::string & key,int32_t & result)557 bool GetIntProperty(napi_env env, napi_value value, const std::string& key, int32_t& result)
558 {
559 CHECK_NULL_RETURN(value, false);
560 napi_valuetype valueType = napi_undefined;
561 napi_value propertyNApi = nullptr;
562 napi_get_named_property(env, value, key.c_str(), &propertyNApi);
563 if (valueType != napi_number) {
564 LOGE("The type of property is incorrect");
565 return false;
566 }
567 int32_t property = 0;
568 napi_status status = napi_get_value_int32(env, propertyNApi, &property);
569 if (status != napi_ok) {
570 LOGE("Get property failed");
571 return false;
572 }
573 return true;
574 }
575
CompleteColorAlphaIfIncomplete(uint32_t origin)576 static uint32_t CompleteColorAlphaIfIncomplete(uint32_t origin)
577 {
578 constexpr uint32_t colorAlphaOffset = 24;
579 constexpr uint32_t colorAlphaDefaultValue = 0xFF000000;
580 uint32_t result = origin;
581 if ((origin >> colorAlphaOffset) == 0) {
582 result = origin | colorAlphaDefaultValue;
583 }
584 return result;
585 }
586
ParseColorFromResourceObject(napi_env env,napi_value value,Color & colorResult)587 bool ParseColorFromResourceObject(napi_env env, napi_value value, Color& colorResult)
588 {
589 ResourceInfo resourceInfo;
590 if (!ParseResourceParam(env, value, resourceInfo)) {
591 LOGE("Parse color from resource failed");
592 return false;
593 }
594 auto themeConstants = GetThemeConstants(resourceInfo.bundleName, resourceInfo.moduleName);
595 if (themeConstants == nullptr) {
596 LOGE("themeConstants is nullptr");
597 return false;
598 }
599 if (resourceInfo.type == static_cast<int32_t>(ResourceType::STRING)) {
600 auto colorString = themeConstants->GetString(resourceInfo.type);
601 return Color::ParseColorString(colorString, colorResult);
602 }
603 if (resourceInfo.type == static_cast<int32_t>(ResourceType::INTEGER)) {
604 auto colorInt = themeConstants->GetInt(resourceInfo.type);
605 colorResult = Color(CompleteColorAlphaIfIncomplete(colorInt));
606 return true;
607 }
608 colorResult = themeConstants->GetColor(resourceInfo.resId);
609 return true;
610 }
611
ParseColor(napi_env env,napi_value value,Color & result)612 bool ParseColor(napi_env env, napi_value value, Color& result)
613 {
614 napi_valuetype valueType = GetValueType(env, value);
615 if (valueType != napi_number && valueType != napi_string && valueType != napi_object) {
616 return false;
617 }
618 if (valueType == napi_number) {
619 int32_t colorId = 0;
620 napi_get_value_int32(env, value, &colorId);
621 result = Color(CompleteColorAlphaIfIncomplete(static_cast<uint32_t>(colorId)));
622 return true;
623 }
624 if (valueType == napi_string) {
625 std::optional<std::string> colorString = GetStringFromValueUtf8(env, value);
626 if (!colorString.has_value()) {
627 LOGE("Parse color from string failed");
628 }
629 return Color::ParseColorString(colorString.value(), result);
630 }
631
632 return ParseColorFromResourceObject(env, value, result);
633 }
634
ParseResourceParam(napi_env env,napi_value value,ResourceInfo & info)635 bool ParseResourceParam(napi_env env, napi_value value, ResourceInfo& info)
636 {
637 CompleteResourceParam(env, value);
638 napi_value idNApi = nullptr;
639 napi_value typeNApi = nullptr;
640 napi_value paramsNApi = nullptr;
641 napi_value bundleNameNApi = nullptr;
642 napi_value moduleNameNApi = nullptr;
643 napi_valuetype valueType = napi_undefined;
644 napi_typeof(env, value, &valueType);
645 if (valueType == napi_object) {
646 napi_get_named_property(env, value, "id", &idNApi);
647 napi_get_named_property(env, value, "type", &typeNApi);
648 napi_get_named_property(env, value, "params", ¶msNApi);
649 napi_get_named_property(env, value, "bundleName", &bundleNameNApi);
650 napi_get_named_property(env, value, "moduleName", &moduleNameNApi);
651 } else {
652 return false;
653 }
654
655 napi_typeof(env, idNApi, &valueType);
656 if (valueType == napi_number) {
657 napi_get_value_int32(env, idNApi, &info.resId);
658 }
659
660 napi_typeof(env, typeNApi, &valueType);
661 if (valueType == napi_number) {
662 napi_get_value_int32(env, typeNApi, &info.type);
663 }
664
665 bool isArray = false;
666 if (napi_is_array(env, paramsNApi, &isArray) != napi_ok) {
667 return false;
668 }
669
670 if (!isArray) {
671 return false;
672 }
673
674 uint32_t arrayLength = 0;
675 napi_get_array_length(env, paramsNApi, &arrayLength);
676
677 for (uint32_t i = 0; i < arrayLength; i++) {
678 size_t ret = 0;
679 napi_value indexValue = nullptr;
680 napi_get_element(env, paramsNApi, i, &indexValue);
681 napi_typeof(env, indexValue, &valueType);
682 if (valueType == napi_string) {
683 size_t strLen = GetParamLen(env, indexValue) + 1;
684 std::unique_ptr<char[]> indexStr = std::make_unique<char[]>(strLen);
685 napi_get_value_string_utf8(env, indexValue, indexStr.get(), strLen, &ret);
686 info.params.emplace_back(indexStr.get());
687 } else if (valueType == napi_number) {
688 int32_t num;
689 napi_get_value_int32(env, indexValue, &num);
690 info.params.emplace_back(std::to_string(num));
691 }
692 }
693
694 napi_typeof(env, bundleNameNApi, &valueType);
695 if (valueType == napi_string) {
696 size_t ret = 0;
697 size_t strLen = GetParamLen(env, bundleNameNApi) + 1;
698 std::unique_ptr<char[]> bundleNameStr = std::make_unique<char[]>(strLen);
699 napi_get_value_string_utf8(env, bundleNameNApi, bundleNameStr.get(), strLen, &ret);
700 info.bundleName = bundleNameStr.get();
701 }
702
703 napi_typeof(env, moduleNameNApi, &valueType);
704 if (valueType == napi_string) {
705 size_t ret = 0;
706 size_t strLen = GetParamLen(env, moduleNameNApi) + 1;
707 std::unique_ptr<char[]> moduleNameStr = std::make_unique<char[]>(strLen);
708 napi_get_value_string_utf8(env, moduleNameNApi, moduleNameStr.get(), strLen, &ret);
709 info.moduleName = moduleNameStr.get();
710 }
711
712 return true;
713 }
714
DimensionToString(Dimension dimension)715 std::string DimensionToString(Dimension dimension)
716 {
717 static const int32_t unitsNum = 6;
718 static const int32_t percentIndex = 3;
719 static const int32_t percentUnit = 100;
720 static std::array<std::string, unitsNum> units = { "px", "vp", "fp", "%", "lpx", "auto" };
721 auto unit = dimension.Unit();
722 auto value = dimension.Value();
723 if (unit == DimensionUnit::NONE) {
724 return StringUtils::DoubleToString(value).append("none");
725 }
726 if (units[static_cast<int>(unit)] == units[percentIndex]) {
727 return StringUtils::DoubleToString(value * percentUnit).append(units[static_cast<int>(unit)]);
728 }
729 return StringUtils::DoubleToString(value).append(units[static_cast<int>(unit)]);
730 }
731
ParseString(const ResourceInfo & info,std::string & result)732 bool ParseString(const ResourceInfo& info, std::string& result)
733 {
734 auto resourceWrapper = CreateResourceWrapper(info);
735 if (info.type == static_cast<int>(ResourceType::PLURAL)) {
736 std::string pluralResults;
737 if (info.resId == UNKNOWN_RESOURCE_ID) {
738 auto count = StringUtils::StringToInt(info.params[1]);
739 pluralResults = resourceWrapper->GetPluralStringByName(info.params[0], count);
740 ReplaceHolder(pluralResults, info.params, 2); // plural holder in index 2
741 } else {
742 auto count = StringUtils::StringToInt(info.params[0]);
743 pluralResults = resourceWrapper->GetPluralString(info.resId, count);
744 ReplaceHolder(pluralResults, info.params, 1);
745 }
746 result = pluralResults;
747 return true;
748 }
749 if (info.type == static_cast<int>(ResourceType::RAWFILE)) {
750 auto fileName = info.params[0];
751 result = resourceWrapper->GetRawfile(fileName);
752 return true;
753 }
754 if (info.type == static_cast<int>(ResourceType::FLOAT)) {
755 if (info.resId == UNKNOWN_RESOURCE_ID) {
756 result = DimensionToString(resourceWrapper->GetDimensionByName(info.params[0]));
757 } else {
758 result = DimensionToString(resourceWrapper->GetDimension(info.resId));
759 }
760 return true;
761 }
762 if (info.type == static_cast<int>(ResourceType::STRING)) {
763 std::string originStr;
764 if (info.resId == UNKNOWN_RESOURCE_ID) {
765 originStr = resourceWrapper->GetStringByName(info.params[0]);
766 ReplaceHolder(originStr, info.params, 1);
767 } else {
768 originStr = resourceWrapper->GetString(info.resId);
769 ReplaceHolder(originStr, info.params, 0);
770 }
771 result = originStr;
772 return true;
773 }
774 if (info.type == static_cast<int>(ResourceType::COLOR)) {
775 result = resourceWrapper->GetColor(info.resId).ColorToString();
776 return true;
777 }
778 return true;
779 }
780
ErrorToMessage(int32_t code)781 std::string ErrorToMessage(int32_t code)
782 {
783 auto iter = ERROR_CODE_TO_MSG.find(code);
784 return (iter != ERROR_CODE_TO_MSG.end()) ? iter->second : "";
785 }
786
GetSingleParam(napi_env env,napi_callback_info info,napi_value * argv,napi_valuetype & valueType)787 bool GetSingleParam(napi_env env, napi_callback_info info, napi_value* argv, napi_valuetype& valueType)
788 {
789 size_t argc = 1;
790 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
791 if (argc != 1) {
792 return false;
793 }
794 napi_typeof(env, argv[0], &valueType);
795 return true;
796 }
797
798 // (Color | number | string | undifened)
GetOptionalColor(napi_env env,napi_value argv,napi_valuetype & valueType)799 std::optional<Color> GetOptionalColor(napi_env env, napi_value argv, napi_valuetype& valueType)
800 {
801 if (valueType == napi_number) {
802 uint32_t num;
803 uint32_t alpha = 0xff000000;
804 napi_get_value_uint32(env, argv, &num);
805 if ((num & alpha) == 0) {
806 num |= alpha;
807 }
808 return Color(num);
809 } else if (valueType == napi_string) {
810 std::string str;
811 bool result = GetNapiString(env, argv, str, valueType);
812 Color color;
813 if (!result || !Color::ParseColorString(str, color)) {
814 return std::nullopt;
815 }
816 return color;
817 } else {
818 return std::nullopt;
819 }
820 }
821
ParseIntegerToString(const ResourceInfo & info,std::string & result)822 bool ParseIntegerToString(const ResourceInfo& info, std::string& result)
823 {
824 auto resourceWrapper = CreateResourceWrapper(info);
825 if (info.type == static_cast<int>(ResourceType::INTEGER)) {
826 if (info.resId == UNKNOWN_RESOURCE_ID) {
827 result = std::to_string(resourceWrapper->GetIntByName(info.params[0]));
828 } else {
829 result = std::to_string(resourceWrapper->GetInt(info.resId));
830 }
831 return true;
832 }
833 return true;
834 }
835
HasProperty(napi_env env,napi_value value,const std::string & targetStr)836 bool HasProperty(napi_env env, napi_value value, const std::string& targetStr)
837 {
838 bool hasProperty = false;
839 napi_has_named_property(env, value, targetStr.c_str(), &hasProperty);
840 return hasProperty;
841 }
842
GetReturnObject(napi_env env,std::string callbackString)843 napi_value GetReturnObject(napi_env env, std::string callbackString)
844 {
845 napi_value result = nullptr;
846 napi_value returnObj = nullptr;
847 napi_create_object(env, &returnObj);
848 napi_create_string_utf8(env, callbackString.c_str(), NAPI_AUTO_LENGTH, &result);
849 napi_set_named_property(env, returnObj, "errMsg", result);
850 return returnObj;
851 }
852
ParseNapiDimension(napi_env env,CalcDimension & result,napi_value napiValue,DimensionUnit defaultUnit)853 bool ParseNapiDimension(napi_env env, CalcDimension& result, napi_value napiValue, DimensionUnit defaultUnit)
854 {
855 napi_valuetype valueType = napi_undefined;
856 napi_typeof(env, napiValue, &valueType);
857 if (valueType == napi_number) {
858 double value = 0;
859 napi_get_value_double(env, napiValue, &value);
860 result.SetUnit(defaultUnit);
861 result.SetValue(value);
862 return true;
863 } else if (valueType == napi_string) {
864 std::string valueString;
865 if (!GetNapiString(env, napiValue, valueString, valueType)) {
866 return false;
867 }
868 result = StringUtils::StringToCalcDimension(valueString, false, defaultUnit);
869 return true;
870 } else if (valueType == napi_object) {
871 ResourceInfo recv;
872 std::string parameterStr;
873 if (!ParseResourceParam(env, napiValue, recv)) {
874 return false;
875 }
876 if (!ParseString(recv, parameterStr)) {
877 return false;
878 }
879 result = StringUtils::StringToDimensionWithUnit(parameterStr, defaultUnit);
880 return true;
881 }
882 return false;
883 }
884
ParseNapiDimensionNG(napi_env env,CalcDimension & result,napi_value napiValue,DimensionUnit defaultUnit,bool isSupportPercent)885 bool ParseNapiDimensionNG(
886 napi_env env, CalcDimension& result, napi_value napiValue, DimensionUnit defaultUnit, bool isSupportPercent)
887 {
888 napi_valuetype valueType = napi_undefined;
889 napi_typeof(env, napiValue, &valueType);
890 if (valueType == napi_number) {
891 double value = 0;
892 napi_get_value_double(env, napiValue, &value);
893
894 result.SetUnit(defaultUnit);
895 result.SetValue(value);
896 return true;
897 } else if (valueType == napi_string) {
898 std::string valueString;
899 if (!GetNapiString(env, napiValue, valueString, valueType)) {
900 return false;
901 }
902 if (valueString.back() == '%' && !isSupportPercent) {
903 return false;
904 }
905 return StringUtils::StringToCalcDimensionNG(valueString, result, false, defaultUnit);
906 } else if (valueType == napi_object) {
907 ResourceInfo recv;
908 std::string parameterStr;
909 if (!ParseResourceParam(env, napiValue, recv)) {
910 return false;
911 }
912 if (!ParseString(recv, parameterStr)) {
913 return false;
914 }
915 if (!ParseIntegerToString(recv, parameterStr)) {
916 return false;
917 }
918 result = StringUtils::StringToDimensionWithUnit(parameterStr, defaultUnit);
919 return true;
920 }
921 return false;
922 }
923
ParseNapiColor(napi_env env,napi_value value,Color & result)924 bool ParseNapiColor(napi_env env, napi_value value, Color& result)
925 {
926 napi_valuetype valueType = GetValueType(env, value);
927 if (valueType != napi_number && valueType != napi_string && valueType != napi_object) {
928 return false;
929 }
930 if (valueType == napi_number) {
931 int32_t colorId = 0;
932 napi_get_value_int32(env, value, &colorId);
933 constexpr uint32_t colorAlphaOffset = 24;
934 constexpr uint32_t colorAlphaDefaultValue = 0xFF000000;
935 auto origin = static_cast<uint32_t>(colorId);
936 uint32_t alphaResult = origin;
937 if ((origin >> colorAlphaOffset) == 0) {
938 alphaResult = origin | colorAlphaDefaultValue;
939 }
940 result = Color(alphaResult);
941 return true;
942 }
943 if (valueType == napi_string) {
944 std::optional<std::string> colorString = GetStringFromValueUtf8(env, value);
945 if (!colorString.has_value()) {
946 LOGE("Parse color from string failed");
947 return false;
948 }
949 return Color::ParseColorString(colorString.value(), result);
950 }
951
952 return ParseColorFromResourceObject(env, value, result);
953 }
954
ParseStyle(napi_env env,napi_value value,std::optional<BorderStyle> & style)955 bool ParseStyle(napi_env env, napi_value value, std::optional<BorderStyle>& style)
956 {
957 napi_valuetype valueType = GetValueType(env, value);
958 if (valueType != napi_number) {
959 return false;
960 }
961 int32_t num;
962 napi_get_value_int32(env, value, &num);
963 style = static_cast<BorderStyle>(num);
964 if (style < BorderStyle::SOLID || style > BorderStyle::NONE) {
965 return false;
966 }
967 return true;
968 }
969
ParseShadowColorStrategy(napi_env env,napi_value value,ShadowColorStrategy & strategy)970 bool ParseShadowColorStrategy(napi_env env, napi_value value, ShadowColorStrategy& strategy)
971 {
972 napi_valuetype valueType = GetValueType(env, value);
973 if (valueType == napi_string) {
974 std::optional<std::string> colorStr = GetStringFromValueUtf8(env, value);
975 if (colorStr.has_value()) {
976 if (colorStr->compare("average") == 0) {
977 strategy = ShadowColorStrategy::AVERAGE;
978 return true;
979 } else if (colorStr->compare("primary") == 0) {
980 strategy = ShadowColorStrategy::PRIMARY;
981 return true;
982 }
983 }
984 }
985 return false;
986 }
987 } // namespace OHOS::Ace::Napi
988