• 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 
19 namespace OHOS::Ace::Napi {
20 using namespace OHOS::Ace;
21 namespace {
22 
23 const std::regex RESOURCE_APP_STRING_PLACEHOLDER(R"(\%((\d+)(\$)){0,1}([dsf]))", std::regex::icase);
24 constexpr int32_t NAPI_BUF_LENGTH = 256;
25 constexpr int32_t UNKNOWN_RESOURCE_ID = -1;
26 constexpr char BUNDLE_NAME[] = "bundleName";
27 std::vector<std::string> RESOURCE_HEADS = { "app", "sys" };
28 } // namespace
29 
30 static 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 
NapiThrow(napi_env env,const std::string & message,int32_t errCode)44 void 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 
ReplaceHolder(std::string & originStr,const std::vector<std::string> & params,uint32_t containCount)61 void 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 
GetParamLen(napi_env env,napi_value param)110 size_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 
NapiStringToString(napi_env env,napi_value value,std::string & retStr)120 bool 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 
GetNapiString(napi_env env,napi_value value,std::string & retStr,napi_valuetype & valueType)138 bool 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 
GetThemeConstants(const std::optional<std::string> & bundleName=std::nullopt,const std::optional<std::string> & moduleName=std::nullopt)154 RefPtr<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 
CreateResourceWrapper(const ResourceInfo & info)178 RefPtr<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>(
188                 bundleName.value_or(""), moduleName.value_or(""), Container::CurrentIdSafely());
189             resourceAdapter = ResourceManager::GetInstance().GetOrCreateResourceAdapter(resourceObject);
190         } else {
191             resourceAdapter = ResourceManager::GetInstance().GetResourceAdapter(Container::CurrentIdSafely());
192         }
193         if (!resourceAdapter) {
194             return nullptr;
195         }
196     } else {
197         themeConstants = GetThemeConstants(info.bundleName, info.moduleName);
198         if (!themeConstants) {
199             return nullptr;
200         }
201     }
202     auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
203     return resourceWrapper;
204 }
205 
CreateNapiString(napi_env env,const std::string & rawStr)206 napi_value CreateNapiString(napi_env env, const std::string& rawStr)
207 {
208     napi_value retVal = nullptr;
209     napi_create_string_utf8(env, rawStr.c_str(), rawStr.length(), &retVal);
210     return retVal;
211 }
212 
ConvertResourceType(const std::string & typeName,ResourceType & resType)213 bool ConvertResourceType(const std::string& typeName, ResourceType& resType)
214 {
215     static const std::unordered_map<std::string, ResourceType> resTypeMap {
216         { "color", ResourceType::COLOR },
217         { "media", ResourceType::MEDIA },
218         { "float", ResourceType::FLOAT },
219         { "string", ResourceType::STRING },
220         { "plural", ResourceType::PLURAL },
221         { "pattern", ResourceType::PATTERN },
222         { "boolean", ResourceType::BOOLEAN },
223         { "integer", ResourceType::INTEGER },
224         { "strarray", ResourceType::STRARRAY },
225         { "intarray", ResourceType::INTARRAY },
226     };
227     auto it = resTypeMap.find(typeName);
228     if (it == resTypeMap.end()) {
229         return false;
230     }
231     resType = it->second;
232     return true;
233 }
234 
ParseDollarResource(napi_env env,napi_value value,ResourceType & resType,std::string & resName,std::string & moduleName)235 bool ParseDollarResource(
236     napi_env env, napi_value value, ResourceType& resType, std::string& resName, std::string& moduleName)
237 {
238     napi_valuetype valueType = napi_undefined;
239     napi_typeof(env, value, &valueType);
240     if (valueType != napi_string) {
241         return false;
242     }
243     std::string resPath;
244     if (!GetNapiString(env, value, resPath, valueType)) {
245         return false;
246     }
247     std::vector<std::string> tokens;
248     StringUtils::StringSplitter(resPath, '.', tokens);
249     // $r format like app.xxx.xxx, has 3 paragraph
250     if (static_cast<int32_t>(tokens.size()) != 3) {
251         return false;
252     }
253     std::string maybeModuleName = tokens[0];
254     // [*] or app/hsp at least has 3 chars
255     if (maybeModuleName.size() < 3) {
256         return false;
257     }
258     char begin = *maybeModuleName.begin();
259     char end = maybeModuleName.at(maybeModuleName.size() - 1);
260     bool headCheckPass = false;
261     if (begin == '[' && end == ']') {
262         // moduleName not include 2 brackets
263         moduleName = maybeModuleName.substr(1, maybeModuleName.size() - 2);
264         headCheckPass = true;
265     }
266     if (std::find(RESOURCE_HEADS.begin(), RESOURCE_HEADS.end(), tokens[0]) == RESOURCE_HEADS.end() && !headCheckPass) {
267         return false;
268     }
269     if (!ConvertResourceType(tokens[1], resType)) {
270         return false;
271     }
272     resName = resPath;
273     return true;
274 }
275 
PreFixEmptyBundleName(napi_env env,napi_value value)276 void PreFixEmptyBundleName(napi_env env, napi_value value)
277 {
278     napi_value bundleNameNApi = nullptr;
279     if (napi_get_named_property(env, value, BUNDLE_NAME, &bundleNameNApi) != napi_ok) {
280         return;
281     }
282     std::string bundleName;
283     NapiStringToString(env, bundleNameNApi, bundleName);
284     if (bundleName.empty()) {
285         auto container = Container::CurrentSafely();
286         CHECK_NULL_VOID(container);
287         bundleName = container->GetBundleName();
288         bundleNameNApi = CreateNapiString(env, bundleName);
289         napi_set_named_property(env, value, BUNDLE_NAME, bundleNameNApi);
290     }
291 }
292 
CheckResourceStruct(napi_env env,napi_value value)293 ResourceStruct CheckResourceStruct(napi_env env, napi_value value)
294 {
295     napi_value idNApi = nullptr;
296     napi_valuetype valueType = napi_undefined;
297     napi_typeof(env, value, &valueType);
298     if (valueType != napi_object) {
299         return ResourceStruct::CONSTANT;
300     }
301     if (napi_get_named_property(env, value, "id", &idNApi) != napi_ok) {
302         return ResourceStruct::CONSTANT;
303     }
304     napi_typeof(env, idNApi, &valueType);
305     if (valueType == napi_string) {
306         return ResourceStruct::DYNAMIC_V1;
307     }
308     if (valueType == napi_number) {
309         int32_t id = 0;
310         napi_get_value_int32(env, idNApi, &id);
311         if (id == UNKNOWN_RESOURCE_ID) {
312             return ResourceStruct::DYNAMIC_V2;
313         }
314     }
315     return ResourceStruct::CONSTANT;
316 }
317 
CompleteResourceParam(napi_env env,napi_value value)318 void CompleteResourceParam(napi_env env, napi_value value)
319 {
320     PreFixEmptyBundleName(env, value);
321     ResourceStruct resourceStruct = CheckResourceStruct(env, value);
322     switch (resourceStruct) {
323         case ResourceStruct::CONSTANT:
324             return;
325         case ResourceStruct::DYNAMIC_V1:
326             CompleteResourceParamV1(env, value);
327             return;
328         case ResourceStruct::DYNAMIC_V2:
329             CompleteResourceParamV2(env, value);
330             return;
331         default:
332             return;
333     }
334 }
335 
CompleteResourceParamV1(napi_env env,napi_value value)336 void CompleteResourceParamV1(napi_env env, napi_value value)
337 {
338     napi_value idNApi = nullptr;
339     napi_valuetype valueType = napi_undefined;
340     napi_typeof(env, value, &valueType);
341     if (valueType != napi_object) {
342         return;
343     }
344     if (napi_get_named_property(env, value, "id", &idNApi) != napi_ok) {
345         return;
346     }
347     std::string resName;
348     std::string moduleName;
349     ResourceType resType;
350     if (!ParseDollarResource(env, idNApi, resType, resName, moduleName)) {
351         return;
352     }
353     bool hasProperty = false;
354     napi_value typeIdNApi = nullptr;
355     napi_value resourceIdNApi = nullptr;
356     napi_value typeKeyNApi = CreateNapiString(env, "type");
357     napi_value defaultNameNApi = CreateNapiString(env, "");
358     napi_value bundleNameKeyNApi = CreateNapiString(env, "bundleName");
359     napi_value moduleNameKeyNApi = CreateNapiString(env, "moduleName");
360     napi_create_int32(env, UNKNOWN_RESOURCE_ID, &resourceIdNApi);
361     napi_create_int32(env, static_cast<uint32_t>(resType), &typeIdNApi);
362     ModifyResourceParam(env, value, resType, resName);
363     napi_set_property(env, value, typeKeyNApi, typeIdNApi);
364     napi_set_property(env, value, CreateNapiString(env, "id"), resourceIdNApi);
365     napi_has_property(env, value, bundleNameKeyNApi, &hasProperty);
366     if (!hasProperty) {
367         napi_set_property(env, value, bundleNameKeyNApi, defaultNameNApi);
368     }
369     napi_has_property(env, value, moduleNameKeyNApi, &hasProperty);
370     if (!hasProperty) {
371         napi_set_property(env, value, moduleNameKeyNApi, defaultNameNApi);
372     }
373 }
374 
CompleteResourceParamV2(napi_env env,napi_value value)375 void CompleteResourceParamV2(napi_env env, napi_value value)
376 {
377     napi_value paramsNApi = nullptr;
378     if (napi_get_named_property(env, value, "params", &paramsNApi) != napi_ok) {
379         return;
380     }
381     bool isArray = false;
382     napi_is_array(env, paramsNApi, &isArray);
383     if (!isArray) {
384         return;
385     }
386     uint32_t paramCount = 0;
387     napi_get_array_length(env, paramsNApi, &paramCount);
388     if (paramCount <= 0) {
389         return;
390     }
391     napi_value resNameNApi = nullptr;
392     napi_get_element(env, paramsNApi, 0, &resNameNApi);
393     std::string resName;
394     std::string moduleName;
395     ResourceType resType;
396     if (!ParseDollarResource(env, resNameNApi, resType, resName, moduleName)) {
397         return;
398     }
399     napi_value typeIdNApi = nullptr;
400     napi_value typeKeyNApi = CreateNapiString(env, "type");
401     napi_create_int32(env, static_cast<uint32_t>(resType), &typeIdNApi);
402     napi_set_property(env, value, typeKeyNApi, typeIdNApi);
403     if (!moduleName.empty()) {
404         napi_value moduleNameNApi = CreateNapiString(env, moduleName);
405         napi_value moduleNameKeyNApi = CreateNapiString(env, "moduleName");
406         napi_set_property(env, value, moduleNameKeyNApi, moduleNameNApi);
407     }
408 }
409 
ModifyResourceParam(napi_env env,napi_value value,const ResourceType & resType,const std::string & resName)410 void ModifyResourceParam(napi_env env, napi_value value, const ResourceType& resType, const std::string& resName)
411 {
412     // raw input : {"id":"app.xxx.xxx","params":[],"moduleName":"xxx","bundleName":"xxx"}
413     // modified output : {"id":-1, "params":["app.xxx.xxx"],"type":xxxx,"moduleName":"xxx","bundleName":"xxx"}
414     napi_value paramsNApi = nullptr;
415     napi_get_named_property(env, value, "params", &paramsNApi);
416     bool isArray = false;
417     if (napi_is_array(env, paramsNApi, &isArray) != napi_ok) {
418         return;
419     }
420     if (!isArray) {
421         return;
422     }
423     uint32_t paramCount = 0;
424     bool hasProperty = false;
425     napi_get_array_length(env, paramsNApi, &paramCount);
426     napi_value typeKeyNApi = CreateNapiString(env, "type");
427     napi_value resNameNApi = CreateNapiString(env, resName);
428     if (resType == ResourceType::PLURAL || resType == ResourceType::STRING) {
429         std::vector<napi_value> tmpParams;
430         for (uint32_t i = 0; i < paramCount; i++) {
431             napi_value param = nullptr;
432             napi_get_element(env, paramsNApi, i, &param);
433             tmpParams.insert(tmpParams.end(), param);
434         }
435         napi_set_element(env, paramsNApi, 0, resNameNApi);
436         uint32_t paramIndex = 1;
437         napi_has_property(env, value, typeKeyNApi, &hasProperty);
438         if (hasProperty) {
439             napi_value firstParam = nullptr;
440             napi_get_property(env, value, typeKeyNApi, &firstParam);
441             napi_set_element(env, paramsNApi, paramIndex, firstParam);
442             paramIndex++;
443         }
444         for (auto tmpParam : tmpParams) {
445             napi_set_element(env, paramsNApi, paramIndex, tmpParam);
446             paramIndex++;
447         }
448     } else {
449         napi_set_element(env, paramsNApi, 0, resNameNApi);
450     }
451 }
452 
ParseCurveInfo(const std::string & curveString,std::string & curveTypeString,std::vector<float> & curveValue)453 void ParseCurveInfo(const std::string& curveString, std::string& curveTypeString, std::vector<float>& curveValue)
454 {
455     if (curveString.back() != ')') {
456         return;
457     }
458     std::string::size_type leftEmbracePosition = curveString.find_last_of('(');
459     if (leftEmbracePosition == std::string::npos) {
460         return;
461     }
462     curveTypeString = curveString.substr(0, leftEmbracePosition);
463     auto params = curveString.substr(leftEmbracePosition + 1, curveString.length() - leftEmbracePosition - 2);
464     if (curveTypeString.empty() || params.empty()) {
465         return;
466     }
467     std::vector<std::string> paramsVector;
468     StringUtils::StringSplitter(params, ',', paramsVector);
469     for (auto& param : paramsVector) {
470         Framework::RemoveHeadTailSpace(param);
471         if (param == "true" || param == "start") {
472             param = "1.000000";
473         }
474         if (param == "false" || param == "end") {
475             param = "0.000000";
476         }
477         errno = 0;
478         char* end = nullptr;
479         float value = strtof(param.c_str(), &end);
480         if (end == param.c_str() || errno == ERANGE) {
481             LOGW("%{public}s can not be converted to float or is out of range.", param.c_str());
482         }
483         curveValue.emplace_back(value);
484     }
485 }
486 
ParseCurve(napi_env env,napi_value value,std::string & curveTypeString,std::vector<float> & curveValue)487 napi_value ParseCurve(napi_env env, napi_value value, std::string& curveTypeString, std::vector<float>& curveValue)
488 {
489     CHECK_NULL_RETURN(value, nullptr);
490     napi_valuetype valueType = napi_undefined;
491     napi_typeof(env, value, &valueType);
492     NAPI_ASSERT(env, valueType == napi_object || valueType == napi_string, "The type of curve is incorrect");
493     if (valueType == napi_object) {
494         napi_value curveObjectNApi = nullptr;
495         napi_get_named_property(env, value, "__curveString", &curveObjectNApi);
496         value = curveObjectNApi;
497     }
498 
499     size_t paramLen = 0;
500     napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &paramLen);
501     NAPI_ASSERT(env, paramLen > 0 && paramLen < NAPI_BUF_LENGTH && status == napi_ok, "paramLen error");
502     char params[NAPI_BUF_LENGTH] = { 0 };
503     status = napi_get_value_string_utf8(env, value, params, paramLen + 1, &paramLen);
504     NAPI_ASSERT(env, status == napi_ok, "Parse curve failed");
505 
506     RefPtr<Curve> curve;
507     const std::string domAnimationDefaultCurveString = "ease-in-out";
508     if (params[0] == '\0') {
509         curve = Framework::CreateCurve(domAnimationDefaultCurveString);
510     } else {
511         curve = Framework::CreateCurve(params);
512     }
513     std::string curveString = curve->ToString();
514     ParseCurveInfo(curveString, curveTypeString, curveValue);
515     return nullptr;
516 }
517 
GetValueType(napi_env env,napi_value value)518 napi_valuetype GetValueType(napi_env env, napi_value value)
519 {
520     if (value == nullptr) {
521         return napi_undefined;
522     }
523 
524     napi_valuetype valueType = napi_undefined;
525     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
526     return valueType;
527 }
528 
GetStringFromValueUtf8(napi_env env,napi_value value)529 std::optional<std::string> GetStringFromValueUtf8(napi_env env, napi_value value)
530 {
531     static constexpr size_t maxLength = 2048;
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 || paramLen > maxLength || status != napi_ok) {
539         return std::nullopt;
540     }
541     char params[maxLength] = { 0 };
542     status = napi_get_value_string_utf8(env, value, params, paramLen + 1, &paramLen);
543     if (status != napi_ok) {
544         return std::nullopt;
545     }
546     return params;
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 themeConstants = GetThemeConstants(resourceInfo.bundleName, resourceInfo.moduleName);
587     if (themeConstants == nullptr) {
588         LOGE("themeConstants is nullptr");
589         return false;
590     }
591     if (resourceInfo.type == static_cast<int32_t>(ResourceType::STRING)) {
592         auto colorString = themeConstants->GetString(resourceInfo.type);
593         return Color::ParseColorString(colorString, colorResult);
594     }
595     if (resourceInfo.type == static_cast<int32_t>(ResourceType::INTEGER)) {
596         auto colorInt = themeConstants->GetInt(resourceInfo.type);
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 = themeConstants->GetColorByName(resourceInfo.params[0]);
606     } else {
607         colorResult = themeConstants->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     if (info.type == static_cast<int>(ResourceType::PLURAL)) {
737         std::string pluralResults;
738         if (info.resId == UNKNOWN_RESOURCE_ID) {
739             auto count = StringUtils::StringToInt(info.params[1]);
740             pluralResults = resourceWrapper->GetPluralStringByName(info.params[0], count);
741             ReplaceHolder(pluralResults, info.params, 2); // plural holder in index 2
742         } else {
743             auto count = StringUtils::StringToInt(info.params[0]);
744             pluralResults = resourceWrapper->GetPluralString(info.resId, count);
745             ReplaceHolder(pluralResults, info.params, 1);
746         }
747         result = pluralResults;
748         return true;
749     }
750     if (info.type == static_cast<int>(ResourceType::RAWFILE)) {
751         auto fileName = info.params[0];
752         result = resourceWrapper->GetRawfile(fileName);
753         return true;
754     }
755     if (info.type == static_cast<int>(ResourceType::FLOAT)) {
756         if (info.resId == UNKNOWN_RESOURCE_ID) {
757             result = DimensionToString(resourceWrapper->GetDimensionByName(info.params[0]));
758         } else {
759             result = DimensionToString(resourceWrapper->GetDimension(info.resId));
760         }
761         return true;
762     }
763     if (info.type == static_cast<int>(ResourceType::STRING)) {
764         std::string originStr;
765         if (info.resId == UNKNOWN_RESOURCE_ID) {
766             originStr = resourceWrapper->GetStringByName(info.params[0]);
767             ReplaceHolder(originStr, info.params, 1);
768         } else {
769             originStr = resourceWrapper->GetString(info.resId);
770             ReplaceHolder(originStr, info.params, 0);
771         }
772         result = originStr;
773         return true;
774     }
775     if (info.type == static_cast<int>(ResourceType::COLOR)) {
776         result = resourceWrapper->GetColor(info.resId).ColorToString();
777         return true;
778     }
779     if (info.type == static_cast<int>(ResourceType::INTEGER)) {
780         result = std::to_string(resourceWrapper->GetInt(info.resId));
781         return true;
782     }
783     return true;
784 }
785 
ErrorToMessage(int32_t code)786 std::string ErrorToMessage(int32_t code)
787 {
788     auto iter = ERROR_CODE_TO_MSG.find(code);
789     return (iter != ERROR_CODE_TO_MSG.end()) ? iter->second : "";
790 }
791 
GetSingleParam(napi_env env,napi_callback_info info,napi_value * argv,napi_valuetype & valueType)792 bool GetSingleParam(napi_env env, napi_callback_info info, napi_value* argv, napi_valuetype& valueType)
793 {
794     size_t argc = 1;
795     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
796     if (argc != 1) {
797         return false;
798     }
799     napi_typeof(env, argv[0], &valueType);
800     return true;
801 }
802 
803 // (Color | number | string | undifened)
GetOptionalColor(napi_env env,napi_value argv,napi_valuetype & valueType)804 std::optional<Color> GetOptionalColor(napi_env env, napi_value argv, napi_valuetype& valueType)
805 {
806     if (valueType == napi_number) {
807         uint32_t num;
808         uint32_t alpha = 0xff000000;
809         napi_get_value_uint32(env, argv, &num);
810         if ((num & alpha) == 0) {
811             num |= alpha;
812         }
813         return Color(num);
814     } else if (valueType == napi_string) {
815         std::string str;
816         bool result = GetNapiString(env, argv, str, valueType);
817         Color color;
818         if (!result || !Color::ParseColorString(str, color)) {
819             return std::nullopt;
820         }
821         return color;
822     } else {
823         return std::nullopt;
824     }
825 }
826 
ParseIntegerToString(const ResourceInfo & info,std::string & result)827 bool ParseIntegerToString(const ResourceInfo& info, std::string& result)
828 {
829     auto resourceWrapper = CreateResourceWrapper(info);
830     if (info.type == static_cast<int>(ResourceType::INTEGER)) {
831         if (info.resId == UNKNOWN_RESOURCE_ID) {
832             result = std::to_string(resourceWrapper->GetIntByName(info.params[0]));
833         } else {
834             result = std::to_string(resourceWrapper->GetInt(info.resId));
835         }
836         return true;
837     }
838     return true;
839 }
840 
HasProperty(napi_env env,napi_value value,const std::string & targetStr)841 bool HasProperty(napi_env env, napi_value value, const std::string& targetStr)
842 {
843     bool hasProperty = false;
844     napi_has_named_property(env, value, targetStr.c_str(), &hasProperty);
845     return hasProperty;
846 }
847 
GetReturnObject(napi_env env,std::string callbackString)848 napi_value GetReturnObject(napi_env env, std::string callbackString)
849 {
850     napi_value result = nullptr;
851     napi_value returnObj = nullptr;
852     napi_create_object(env, &returnObj);
853     napi_create_string_utf8(env, callbackString.c_str(), NAPI_AUTO_LENGTH, &result);
854     napi_set_named_property(env, returnObj, "errMsg", result);
855     return returnObj;
856 }
857 
ParseNapiDimension(napi_env env,CalcDimension & result,napi_value napiValue,DimensionUnit defaultUnit)858 bool ParseNapiDimension(napi_env env, CalcDimension& result, napi_value napiValue, DimensionUnit defaultUnit)
859 {
860     napi_valuetype valueType = napi_undefined;
861     napi_typeof(env, napiValue, &valueType);
862     if (valueType == napi_number) {
863         double value = 0;
864         napi_get_value_double(env, napiValue, &value);
865         result.SetUnit(defaultUnit);
866         result.SetValue(value);
867         return true;
868     } else if (valueType == napi_string) {
869         std::string valueString;
870         if (!GetNapiString(env, napiValue, valueString, valueType)) {
871             return false;
872         }
873         result = StringUtils::StringToCalcDimension(valueString, false, defaultUnit);
874         return true;
875     } else if (valueType == napi_object) {
876         ResourceInfo recv;
877         std::string parameterStr;
878         if (!ParseResourceParam(env, napiValue, recv)) {
879             return false;
880         }
881         if (!ParseString(recv, parameterStr)) {
882             return false;
883         }
884         result = StringUtils::StringToDimensionWithUnit(parameterStr, defaultUnit);
885         return true;
886     }
887     return false;
888 }
889 
ParseNapiDimensionNG(napi_env env,CalcDimension & result,napi_value napiValue,DimensionUnit defaultUnit,bool isSupportPercent)890 bool ParseNapiDimensionNG(
891     napi_env env, CalcDimension& result, napi_value napiValue, DimensionUnit defaultUnit, bool isSupportPercent)
892 {
893     napi_valuetype valueType = napi_undefined;
894     napi_typeof(env, napiValue, &valueType);
895     if (valueType == napi_number) {
896         double value = 0;
897         napi_get_value_double(env, napiValue, &value);
898 
899         result.SetUnit(defaultUnit);
900         result.SetValue(value);
901         return true;
902     } else if (valueType == napi_string) {
903         std::string valueString;
904         if (!GetNapiString(env, napiValue, valueString, valueType)) {
905             return false;
906         }
907         if (valueString.back() == '%' && !isSupportPercent) {
908             return false;
909         }
910         return StringUtils::StringToCalcDimensionNG(valueString, result, false, defaultUnit);
911     } else if (valueType == napi_object) {
912         ResourceInfo recv;
913         std::string parameterStr;
914         if (!ParseResourceParam(env, napiValue, recv)) {
915             return false;
916         }
917         if (!ParseString(recv, parameterStr)) {
918             return false;
919         }
920         if (!ParseIntegerToString(recv, parameterStr)) {
921             return false;
922         }
923         result = StringUtils::StringToDimensionWithUnit(parameterStr, defaultUnit);
924         return true;
925     }
926     return false;
927 }
928 
ParseNapiColor(napi_env env,napi_value value,Color & result)929 bool ParseNapiColor(napi_env env, napi_value value, Color& result)
930 {
931     napi_valuetype valueType = GetValueType(env, value);
932     if (valueType != napi_number && valueType != napi_string && valueType != napi_object) {
933         return false;
934     }
935     if (valueType == napi_number) {
936         int32_t colorId = 0;
937         napi_get_value_int32(env, value, &colorId);
938         constexpr uint32_t colorAlphaOffset = 24;
939         constexpr uint32_t colorAlphaDefaultValue = 0xFF000000;
940         auto origin = static_cast<uint32_t>(colorId);
941         uint32_t alphaResult = origin;
942         if ((origin >> colorAlphaOffset) == 0) {
943             alphaResult = origin | colorAlphaDefaultValue;
944         }
945         result = Color(alphaResult);
946         return true;
947     }
948     if (valueType == napi_string) {
949         std::optional<std::string> colorString = GetStringFromValueUtf8(env, value);
950         if (!colorString.has_value()) {
951             LOGE("Parse color from string failed");
952             return false;
953         }
954         return Color::ParseColorString(colorString.value(), result);
955     }
956 
957     return ParseColorFromResourceObject(env, value, result);
958 }
959 
ParseStyle(napi_env env,napi_value value,std::optional<BorderStyle> & style)960 bool ParseStyle(napi_env env, napi_value value, std::optional<BorderStyle>& style)
961 {
962     napi_valuetype valueType = GetValueType(env, value);
963     if (valueType != napi_number) {
964         return false;
965     }
966     int32_t num;
967     napi_get_value_int32(env, value, &num);
968     style = static_cast<BorderStyle>(num);
969     if (style < BorderStyle::SOLID || style > BorderStyle::NONE) {
970         return false;
971     }
972     return true;
973 }
974 
ParseShadowColorStrategy(napi_env env,napi_value value,ShadowColorStrategy & strategy)975 bool ParseShadowColorStrategy(napi_env env, napi_value value, ShadowColorStrategy& strategy)
976 {
977     napi_valuetype valueType = GetValueType(env, value);
978     if (valueType == napi_string) {
979         std::optional<std::string> colorStr = GetStringFromValueUtf8(env, value);
980         if (colorStr.has_value()) {
981             if (colorStr->compare("average") == 0) {
982                 strategy = ShadowColorStrategy::AVERAGE;
983                 return true;
984             } else if (colorStr->compare("primary") == 0) {
985                 strategy = ShadowColorStrategy::PRIMARY;
986                 return true;
987             }
988         }
989     }
990     return false;
991 }
992 } // namespace OHOS::Ace::Napi
993