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