• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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", &paramsNApi) != 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, &paramCount);
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", &paramsNApi);
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, &paramCount);
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, &param);
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, &paramLen);
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, &paramLen);
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, &paramLen);
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, &paramLen);
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", &paramsNApi);
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