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