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