1 /*
2 * Copyright (c) 2021-2022 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
18 namespace OHOS::Ace::Napi {
19 namespace {
20
21 enum class ResourceType : uint32_t {
22 COLOR = 10001,
23 FLOAT,
24 STRING,
25 PLURAL,
26 BOOLEAN,
27 INTARRAY,
28 INTEGER,
29 PATTERN,
30 STRARRAY,
31 MEDIA = 20000,
32 RAWFILE = 30000
33 };
34
35 const std::regex RESOURCE_APP_STRING_PLACEHOLDER(R"(\%((\d+)(\$)){0,1}([dsf]))", std::regex::icase);
36
37 } // namespace
38
39 static const std::unordered_map<int32_t, std::string> ERROR_CODE_TO_MSG {
40 { Framework::ERROR_CODE_PERMISSION_DENIED, "Permission denied. " },
41 { Framework::ERROR_CODE_PARAM_INVALID, "Parameter error. " },
42 { Framework::ERROR_CODE_SYSTEMCAP_ERROR, "Capability not supported. " },
43 { Framework::ERROR_CODE_INTERNAL_ERROR, "Internal error. " },
44 { Framework::ERROR_CODE_URI_ERROR, "Uri error. " },
45 { Framework::ERROR_CODE_PAGE_STACK_FULL, "Page stack error. " },
46 { Framework::ERROR_CODE_URI_ERROR_LITE, "Uri error. " }
47 };
48
NapiThrow(napi_env env,const std::string & message,int32_t errCode)49 void NapiThrow(napi_env env, const std::string& message, int32_t errCode)
50 {
51 napi_value code = nullptr;
52 std::string strCode = std::to_string(errCode);
53 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
54
55 napi_value msg = nullptr;
56 auto iter = ERROR_CODE_TO_MSG.find(errCode);
57 std::string strMsg = (iter != ERROR_CODE_TO_MSG.end() ? iter->second : "") + message;
58 LOGE("napi throw errCode %d strMsg %s", errCode, strMsg.c_str());
59 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
60
61 napi_value error = nullptr;
62 napi_create_error(env, code, msg, &error);
63 napi_throw(env, error);
64 }
65
ReplaceHolder(std::string & originStr,std::vector<std::string> & params,int32_t containCount)66 void ReplaceHolder(std::string& originStr, std::vector<std::string>& params, int32_t containCount)
67 {
68 auto size = static_cast<int32_t>(params.size());
69 if (containCount == size) {
70 return;
71 }
72 std::string::const_iterator start = originStr.begin();
73 std::string::const_iterator end = originStr.end();
74 std::smatch matches;
75 bool shortHolderType = false;
76 bool firstMatch = true;
77 int searchTime = 0;
78 while (std::regex_search(start, end, matches, RESOURCE_APP_STRING_PLACEHOLDER)) {
79 std::string pos = matches[2];
80 std::string type = matches[4];
81 if (firstMatch) {
82 firstMatch = false;
83 shortHolderType = pos.length() == 0;
84 } else {
85 if (static_cast<uint32_t>(shortHolderType) ^ ((uint32_t)(pos.length() == 0))) {
86 LOGE("wrong place holder,stop parse string");
87 return;
88 }
89 }
90
91 std::string replaceContentStr;
92 std::string::size_type index;
93 if (shortHolderType) {
94 index = static_cast<uint32_t>(searchTime + containCount);
95 } else {
96 index = static_cast<uint32_t>(StringUtils::StringToInt(pos) - 1 + containCount);
97 }
98 replaceContentStr = params[index];
99
100 originStr.replace(matches[0].first - originStr.begin(), matches[0].length(), replaceContentStr);
101 start = originStr.begin() + matches.prefix().length() + replaceContentStr.length();
102 end = originStr.end();
103 searchTime++;
104 }
105 }
106
GetParamLen(napi_value param)107 size_t GetParamLen(napi_value param)
108 {
109 auto nativeValue = reinterpret_cast<NativeValue*>(param);
110 auto resultValue = nativeValue->ToString();
111 auto nativeString = reinterpret_cast<NativeString*>(resultValue->GetInterface(NativeString::INTERFACE_ID));
112 size_t len = nativeString->GetLength();
113 return len;
114 }
115
GetThemeConstants()116 RefPtr<ThemeConstants> GetThemeConstants()
117 {
118 auto container = Container::Current();
119 if (!container) {
120 LOGW("container is null");
121 return nullptr;
122 }
123 auto pipelineContext = container->GetPipelineContext();
124 if (!pipelineContext) {
125 LOGE("pipelineContext is null!");
126 return nullptr;
127 }
128 auto themeManager = pipelineContext->GetThemeManager();
129 if (!themeManager) {
130 LOGE("themeManager is null!");
131 return nullptr;
132 }
133 return themeManager->GetThemeConstants();
134 }
135
ParseResourceParam(napi_env env,napi_value value,int32_t & id,int32_t & type,std::vector<std::string> & params)136 bool ParseResourceParam(napi_env env, napi_value value, int32_t& id, int32_t& type, std::vector<std::string>& params)
137 {
138 napi_value idNApi = nullptr;
139 napi_value typeNApi = nullptr;
140 napi_value paramsNApi = nullptr;
141 napi_valuetype valueType = napi_undefined;
142 napi_typeof(env, value, &valueType);
143 if (valueType == napi_object) {
144 napi_get_named_property(env, value, "id", &idNApi);
145 napi_get_named_property(env, value, "type", &typeNApi);
146 napi_get_named_property(env, value, "params", ¶msNApi);
147 } else {
148 return false;
149 }
150
151 napi_typeof(env, idNApi, &valueType);
152 if (valueType == napi_number) {
153 napi_get_value_int32(env, idNApi, &id);
154 }
155
156 napi_typeof(env, typeNApi, &valueType);
157 if (valueType == napi_number) {
158 napi_get_value_int32(env, typeNApi, &type);
159 }
160
161 bool isArray = false;
162 if (napi_is_array(env, paramsNApi, &isArray) != napi_ok) {
163 return false;
164 }
165
166 if (!isArray) {
167 return false;
168 }
169
170 uint32_t arrayLength = 0;
171 napi_get_array_length(env, paramsNApi, &arrayLength);
172
173 for (uint32_t i = 0; i < arrayLength; i++) {
174 size_t ret = 0;
175 napi_value indexValue = nullptr;
176 napi_get_element(env, paramsNApi, i, &indexValue);
177 napi_typeof(env, indexValue, &valueType);
178 if (valueType == napi_string) {
179 size_t strLen = GetParamLen(indexValue) + 1;
180 std::unique_ptr<char[]> indexStr = std::make_unique<char[]>(strLen);
181 napi_get_value_string_utf8(env, indexValue, indexStr.get(), strLen, &ret);
182 params.emplace_back(indexStr.get());
183 } else if (valueType == napi_number) {
184 int32_t num;
185 napi_get_value_int32(env, indexValue, &num);
186 params.emplace_back(std::to_string(num));
187 }
188 }
189 return true;
190 }
191
ParseString(int32_t resId,int32_t type,std::vector<std::string> & params,std::string & result)192 bool ParseString(int32_t resId, int32_t type, std::vector<std::string>& params, std::string& result)
193 {
194 auto themeConstants = GetThemeConstants();
195 if (!themeConstants) {
196 LOGE("themeConstants is nullptr");
197 return false;
198 }
199
200 if (type == static_cast<int>(ResourceType::PLURAL)) {
201 auto count = StringUtils::StringToDouble(params[0]);
202 auto pluralResults = themeConstants->GetStringArray(resId);
203 auto pluralChoice = Localization::GetInstance()->PluralRulesFormat(count);
204 auto iter = std::find(pluralResults.begin(), pluralResults.end(), pluralChoice);
205 std::string originStr;
206 if (iter != pluralResults.end() && ++iter != pluralResults.end()) {
207 originStr = *iter;
208 }
209 ReplaceHolder(originStr, params, 1);
210 result = originStr;
211 } else {
212 auto originStr = themeConstants->GetString(resId);
213 ReplaceHolder(originStr, params, 0);
214 result = originStr;
215 }
216 return true;
217 }
218
ErrorToMessage(int32_t code)219 std::string ErrorToMessage(int32_t code)
220 {
221 auto iter = ERROR_CODE_TO_MSG.find(code);
222 return (iter != ERROR_CODE_TO_MSG.end()) ? iter->second : "";
223 }
224
225 } // namespace OHOS::Ace::Napi
226