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 "base/resource/ace_res_key_parser.h"
17 
18 #ifdef WINDOWS_PLATFORM
19 #include <cstdio>
20 #else
21 #include "securec.h"
22 #endif
23 #include <regex>
24 #include "base/utils/string_utils.h"
25 
26 namespace OHOS::Ace {
27 namespace {
28 
29 constexpr int32_t MCC_MNC_KEYWORD_LEN = 3;
30 constexpr int32_t MCC_MNC_VALUE_LEN = 3;
31 constexpr int32_t MAX_MCC_MNC_LEN = 8;
32 
33 const std::unordered_map<std::string, ResolutionType> RES_RESOLUTION = {
34     { "ldpi", ResolutionType::RESOLUTION_LDPI },
35     { "mdpi", ResolutionType::RESOLUTION_MDPI },
36     { "hdpi", ResolutionType::RESOLUTION_HDPI },
37     { "xhdpi", ResolutionType::RESOLUTION_XHDPI },
38     { "xxhdpi", ResolutionType::RESOLUTION_XXHDPI },
39     { "xxxhdpi", ResolutionType::RESOLUTION_XXXHDPI },
40 };
41 
42 const std::unordered_map<std::string, DeviceOrientation> RES_ORIENTATION = {
43     { "horizontal", DeviceOrientation::LANDSCAPE }, { "vertical", DeviceOrientation::PORTRAIT }
44 };
45 
46 const std::unordered_map<std::string, ColorMode> RES_COLOR_MODE = {
47     { "dark", ColorMode::DARK },
48 };
49 
50 const std::unordered_map<std::string, ColorMode> DECLARATIVE_RES_COLOR_MODE = {
51     { "dark", ColorMode::DARK },
52     { "light", ColorMode::LIGHT },
53 };
54 
55 const std::unordered_map<std::string, DeviceType> RES_DEVICE_TYPE = {
56     { "phone", DeviceType::PHONE },
57     { "tablet", DeviceType::TABLET },
58     { "tv", DeviceType::TV },
59     { "wearable", DeviceType::WATCH },
60 };
61 
62 const std::unordered_map<std::string, ScreenShape> RES_SCREEN_SHAPE = {
63     { "round", ScreenShape::ROUND },
64     { "notround", ScreenShape::NOT_ROUND },
65 };
66 
67 const std::unordered_map<std::string, LongScreenType> RES_LONG_SCREEN = {
68     { "long", LongScreenType::LONG },
69     { "notlong", LongScreenType::NOT_LONG },
70 };
71 
72 } // namespace
73 
74 AceResKeyParser::AceResKeyParser() = default;
75 AceResKeyParser::~AceResKeyParser() = default;
76 
Parse(const std::string & deviceResConfigTag,std::vector<KeyParam> & keyParams,bool styleRes)77 bool AceResKeyParser::Parse(const std::string& deviceResConfigTag, std::vector<KeyParam>& keyParams, bool styleRes)
78 {
79     std::vector<std::string> keyParts;
80     StringUtils::StringSplitter(deviceResConfigTag, '-', keyParts);
81 
82     static parse_key_function functions[] = {
83         ParseMcc,
84         ParseMnc,
85         ParseOrientation,
86         ParseColorMode,
87         ParseDeviceType,
88         ParseResolution,
89         ParseDefaults,
90     };
91     const int32_t FUNC_LEN = static_cast<int32_t>(sizeof(functions) / sizeof(functions[0]));
92     if (!keyParts.empty()) {
93         if (!ParseMatch(keyParts, keyParams, functions, FUNC_LEN, styleRes)) {
94             LOGW("Invalid config:%{public}s", deviceResConfigTag.c_str());
95             return false;
96         }
97         return true;
98     }
99     return false;
100 }
101 
DeclarativeParse(const std::string & deviceResConfigTag,std::vector<KeyParam> & keyParams)102 bool AceResKeyParser::DeclarativeParse(const std::string& deviceResConfigTag, std::vector<KeyParam>& keyParams)
103 {
104     std::vector<std::string> reskeyParts;
105     std::string resConfigTag(deviceResConfigTag);
106     StringUtils::StringSplitter(resConfigTag, '-', reskeyParts);
107 
108     static parse_key_function functions[] = {
109         ParseLongScreen,
110         ParseScreenShape,
111         ParseOrientation,
112         ParseDeclarativeColorMode,
113         ParseDeviceType,
114         ParseResolution,
115         ParseDefaults,
116     };
117     const int32_t FUNC_LEN = static_cast<int32_t>(sizeof(functions) / sizeof(functions[0]));
118     if (!reskeyParts.empty()) {
119         if (!ParseMatch(reskeyParts, keyParams, functions, FUNC_LEN, true)) {
120             LOGW("Invalid config:%{public}s", resConfigTag.c_str());
121             return false;
122         }
123         return true;
124     }
125     return false;
126 }
127 
ParseMatch(const std::vector<std::string> & keys,std::vector<KeyParam> & keyParams,parse_key_function functions[],int32_t funcLen,bool styleRes) const128 bool AceResKeyParser::ParseMatch(const std::vector<std::string>& keys, std::vector<KeyParam>& keyParams,
129     parse_key_function functions[], int32_t funcLen, bool styleRes) const
130 {
131     for (auto iter = keys.begin(); iter != keys.end(); iter++) {
132         if (iter == keys.begin() && !styleRes) {
133             if (*iter == "res") {
134                 continue;
135             } else {
136                 return false;
137             }
138         }
139         bool parseRet = false;
140         for (int32_t k = 0; k < funcLen; k++) {
141             if (functions[k](*iter, keyParams)) {
142                 parseRet = true;
143                 break;
144             }
145         }
146         if (!parseRet) {
147             return false;
148         }
149     }
150     return true;
151 }
152 
ParseMcc(const std::string & key,std::vector<KeyParam> & keyParams)153 bool AceResKeyParser::ParseMcc(const std::string& key, std::vector<KeyParam>& keyParams)
154 {
155     std::regex mcc("mcc(\\d{3})");
156     if (regex_match(key, mcc)) {
157         KeyParam keyParam;
158         keyParam.value = StringUtils::StringToInt(key.substr(MCC_MNC_KEYWORD_LEN));
159         keyParam.keyType = KeyType::MCC;
160         keyParams.emplace_back(keyParam);
161         return true;
162     }
163     return false;
164 }
165 
ParseMnc(const std::string & key,std::vector<KeyParam> & keyParams)166 bool AceResKeyParser::ParseMnc(const std::string& key, std::vector<KeyParam>& keyParams)
167 {
168     std::regex mnc("mnc(\\d{2,3})");
169     if (regex_match(key, mnc)) {
170         KeyParam keyParam;
171         keyParam.value = StringUtils::StringToInt(key.substr(MCC_MNC_KEYWORD_LEN));
172         if (key.substr(MCC_MNC_KEYWORD_LEN).length() == MCC_MNC_VALUE_LEN) {
173             keyParam.keyType = KeyType::MNC;
174         } else {
175             keyParam.keyType = KeyType::MNC_SHORT_LEN;
176         }
177         keyParams.emplace_back(keyParam);
178         return true;
179     }
180     return false;
181 }
182 
ParseScreenShape(const std::string & key,std::vector<KeyParam> & keyParams)183 bool AceResKeyParser::ParseScreenShape(const std::string& key, std::vector<KeyParam>& keyParams)
184 {
185     auto iter = RES_SCREEN_SHAPE.find(key);
186     if (iter != RES_SCREEN_SHAPE.end()) {
187         KeyParam keyParam;
188         keyParam.keyType = KeyType::SCREENSHAPE;
189         keyParam.value = static_cast<int32_t>(iter->second);
190         keyParams.emplace_back(keyParam);
191         return true;
192     }
193     return false;
194 }
195 
ParseLongScreen(const std::string & key,std::vector<KeyParam> & keyParams)196 bool AceResKeyParser::ParseLongScreen(const std::string& key, std::vector<KeyParam>& keyParams)
197 {
198     auto iter = RES_LONG_SCREEN.find(key);
199     if (iter != RES_LONG_SCREEN.end()) {
200         KeyParam keyParam;
201         keyParam.keyType = KeyType::LONGSCREEN;
202         keyParam.value = static_cast<int32_t>(iter->second);
203         keyParams.emplace_back(keyParam);
204         return true;
205     }
206     return false;
207 }
208 
ParseOrientation(const std::string & key,std::vector<KeyParam> & keyParams)209 bool AceResKeyParser::ParseOrientation(const std::string& key, std::vector<KeyParam>& keyParams)
210 {
211     auto iter = RES_ORIENTATION.find(key);
212     if (iter != RES_ORIENTATION.end()) {
213         KeyParam keyParam;
214         keyParam.keyType = KeyType::ORIENTATION;
215         keyParam.value = static_cast<int32_t>(iter->second);
216         keyParams.emplace_back(keyParam);
217         return true;
218     }
219     return false;
220 }
221 
ParseColorMode(const std::string & key,std::vector<KeyParam> & keyParams)222 bool AceResKeyParser::ParseColorMode(const std::string& key, std::vector<KeyParam>& keyParams)
223 {
224     auto iter = RES_COLOR_MODE.find(key);
225     if (iter != RES_COLOR_MODE.end()) {
226         KeyParam keyParam;
227         keyParam.keyType = KeyType::COLOR_MODE;
228         keyParam.value = static_cast<int32_t>(iter->second);
229         keyParams.emplace_back(keyParam);
230         return true;
231     }
232     return false;
233 }
234 
ParseDeclarativeColorMode(const std::string & key,std::vector<KeyParam> & keyParams)235 bool AceResKeyParser::ParseDeclarativeColorMode(const std::string& key, std::vector<KeyParam>& keyParams)
236 {
237     auto iter = DECLARATIVE_RES_COLOR_MODE.find(key);
238     if (iter != DECLARATIVE_RES_COLOR_MODE.end()) {
239         KeyParam keyParam;
240         keyParam.keyType = KeyType::DECLARATIVE_COLOR_MODE;
241         keyParam.value = static_cast<int32_t>(iter->second);
242         keyParams.emplace_back(keyParam);
243         return true;
244     }
245     return false;
246 }
247 
ParseDeviceType(const std::string & key,std::vector<KeyParam> & keyParams)248 bool AceResKeyParser::ParseDeviceType(const std::string& key, std::vector<KeyParam>& keyParams)
249 {
250     auto iter = RES_DEVICE_TYPE.find(key);
251     if (iter != RES_DEVICE_TYPE.end()) {
252         KeyParam keyParam;
253         keyParam.keyType = KeyType::DEVICETYPE;
254         keyParam.value = static_cast<int32_t>(iter->second);
255         keyParams.emplace_back(keyParam);
256         return true;
257     }
258     return false;
259 }
260 
ParseResolution(const std::string & key,std::vector<KeyParam> & keyParams)261 bool AceResKeyParser::ParseResolution(const std::string& key, std::vector<KeyParam>& keyParams)
262 {
263     auto iter = RES_RESOLUTION.find(key);
264     if (iter != RES_RESOLUTION.end()) {
265         KeyParam keyParam;
266         keyParam.keyType = KeyType::RESOLUTION;
267         keyParam.value = static_cast<int32_t>(iter->second);
268         keyParams.emplace_back(keyParam);
269         return true;
270     }
271     return false;
272 }
273 
ParseDefaults(const std::string & key,std::vector<KeyParam> & keyParams)274 bool AceResKeyParser::ParseDefaults(const std::string& key, std::vector<KeyParam>& keyParams)
275 {
276     return key == "defaults" || key == "default";
277 }
278 
GetMccByValue(uint32_t value) const279 std::string AceResKeyParser::GetMccByValue(uint32_t value) const
280 {
281     char mccStr[MAX_MCC_MNC_LEN] = { 0 };
282     if (sprintf_s(mccStr, MAX_MCC_MNC_LEN, "mcc%03u", value) < 0) {
283         return "";
284     }
285     return std::string(mccStr);
286 }
287 
GetMncShortLenByValue(uint32_t value) const288 std::string AceResKeyParser::GetMncShortLenByValue(uint32_t value) const
289 {
290     char mncStr[MAX_MCC_MNC_LEN] = { 0 };
291     if (sprintf_s(mncStr, MAX_MCC_MNC_LEN, "mnc%02u", value) < 0) {
292         return "";
293     }
294     return std::string(mncStr);
295 }
296 
GetMncByValue(uint32_t value) const297 std::string AceResKeyParser::GetMncByValue(uint32_t value) const
298 {
299     char mncStr[MAX_MCC_MNC_LEN] = { 0 };
300     if (sprintf_s(mncStr, MAX_MCC_MNC_LEN, "mnc%03u", value) < 0) {
301         return "";
302     }
303     return std::string(mncStr);
304 }
305 
GetOrientationByType(DeviceOrientation type) const306 std::string AceResKeyParser::GetOrientationByType(DeviceOrientation type) const
307 {
308     auto item =
309         find_if(RES_ORIENTATION.begin(), RES_ORIENTATION.end(), [type](auto iter) { return iter.second == type; });
310     if (item != RES_ORIENTATION.end()) {
311         return item->first;
312     }
313     return "";
314 }
315 
GetColorModeByType(ColorMode type) const316 std::string AceResKeyParser::GetColorModeByType(ColorMode type) const
317 {
318     auto item =
319         find_if(RES_COLOR_MODE.begin(), RES_COLOR_MODE.end(), [type](auto iter) { return iter.second == type; });
320     if (item != RES_COLOR_MODE.end()) {
321         return item->first;
322     }
323     return "";
324 }
325 
GetDeclarativeColorModeByType(ColorMode type) const326 std::string AceResKeyParser::GetDeclarativeColorModeByType(ColorMode type) const
327 {
328     auto item = find_if(DECLARATIVE_RES_COLOR_MODE.begin(), DECLARATIVE_RES_COLOR_MODE.end(),
329         [type](auto iter) { return iter.second == type; });
330     if (item != DECLARATIVE_RES_COLOR_MODE.end()) {
331         return item->first;
332     }
333     return "";
334 }
335 
GetDeviceByType(DeviceType type) const336 std::string AceResKeyParser::GetDeviceByType(DeviceType type) const
337 {
338     auto deviceTypeItem =
339         find_if(RES_DEVICE_TYPE.begin(), RES_DEVICE_TYPE.end(), [type](auto iter) { return iter.second == type; });
340     if (deviceTypeItem != RES_DEVICE_TYPE.end()) {
341         return deviceTypeItem->first;
342     }
343     return "";
344 }
345 
GetResolutionByType(ResolutionType type) const346 std::string AceResKeyParser::GetResolutionByType(ResolutionType type) const
347 {
348     auto resolutionItem =
349         find_if(RES_RESOLUTION.begin(), RES_RESOLUTION.end(), [type](auto iter) { return iter.second == type; });
350     if (resolutionItem != RES_RESOLUTION.end()) {
351         return resolutionItem->first;
352     }
353     return "";
354 }
GetScreenShapeByType(ScreenShape type) const355 std::string AceResKeyParser::GetScreenShapeByType(ScreenShape type) const
356 {
357     auto shapeItem =
358         find_if(RES_SCREEN_SHAPE.begin(), RES_SCREEN_SHAPE.end(), [type](auto iter) { return iter.second == type; });
359     if (shapeItem != RES_SCREEN_SHAPE.end()) {
360         return shapeItem->first;
361     }
362     return "";
363 }
364 
GetScreenLongByType(LongScreenType type) const365 std::string AceResKeyParser::GetScreenLongByType(LongScreenType type) const
366 {
367     auto longItem =
368         find_if(RES_LONG_SCREEN.begin(), RES_LONG_SCREEN.end(), [type](auto iter) { return iter.second == type; });
369     if (longItem != RES_LONG_SCREEN.end()) {
370         return longItem->first;
371     }
372     return "";
373 }
374 
375 } // namespace OHOS::Ace