1 /*
2 * Copyright (c) 2024 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 #include "router_map_helper.h"
16 #include "regex.h"
17 #include "app_log_wrapper.h"
18 #include "router_item_compare.h"
19
20 namespace OHOS {
21 namespace AppExecFwk {
22 namespace {
23 const char* ALNUM_PATTERN = "^[a-zA-Z0-9]*$";
24 const char* NUM_PATTERN = "^[0-9]+$";
25 }
26
MergeRouter(BundleInfo & info)27 void RouterMapHelper::MergeRouter(BundleInfo &info)
28 {
29 if (info.hapModuleInfos.empty()) {
30 APP_LOGW("hapModuleInfos in bundleInfo is empty");
31 return;
32 }
33 std::vector<RouterItem> routerArrayList;
34 std::set<std::string> moduleNameSet;
35 for (const auto &hapModuleInfo : info.hapModuleInfos) {
36 if (hapModuleInfo.moduleType == ModuleType::ENTRY || hapModuleInfo.moduleType == ModuleType::FEATURE) {
37 moduleNameSet.insert(hapModuleInfo.name);
38 }
39 for (const auto &routerItem : hapModuleInfo.routerArray) {
40 routerArrayList.emplace_back(routerItem);
41 }
42 }
43 if (routerArrayList.empty()) {
44 return;
45 }
46 MergeRouter(routerArrayList, info.routerArray, moduleNameSet);
47 }
48
ExtractVersionFromOhmurl(const std::string & ohmurl)49 std::string RouterMapHelper::ExtractVersionFromOhmurl(const std::string &ohmurl)
50 {
51 size_t lastAmpersandPos = ohmurl.rfind('&');
52 std::string versionString;
53 if (lastAmpersandPos == std::string::npos) {
54 APP_LOGI_NOFUNC("No ampersand found in the input ohmurl");
55 return versionString;
56 }
57 // "+1" for start intercepting after the "&" character
58 versionString = ohmurl.substr(lastAmpersandPos + 1);
59 return versionString;
60 }
61
MergeRouter(const std::vector<RouterItem> & routerArrayList,std::vector<RouterItem> & routerArray,const std::set<std::string> & moduleNameSet)62 void RouterMapHelper::MergeRouter(const std::vector<RouterItem>& routerArrayList,
63 std::vector<RouterItem>& routerArray, const std::set<std::string>& moduleNameSet)
64 {
65 std::map<RouterItem, std::string, RouterItemCompare> routerMap((RouterItemCompare(moduleNameSet)));
66
67 for (const auto& item : routerArrayList) {
68 routerMap.emplace(item, item.name);
69 }
70
71 std::vector<RouterItem> routerArraySorted;
72
73 routerArraySorted.reserve(routerMap.size());
74 for (const auto& pair : routerMap) {
75 routerArraySorted.push_back(pair.first);
76 }
77 routerArray.clear();
78 for (size_t i = 0; i < routerArraySorted.size(); i++) {
79 if ((i == 0) || (routerArraySorted[i].name != routerArray[routerArray.size() - 1].name)) {
80 routerArray.emplace_back(routerArraySorted[i]);
81 }
82 }
83 }
84
IsRegexMatch(const std::string & str,const char * pattern)85 bool RouterMapHelper::IsRegexMatch(const std::string& str, const char* pattern)
86 {
87 regex_t regex;
88 if (regcomp(®ex, pattern, REG_EXTENDED | REG_NOSUB) != 0) {
89 APP_LOGE("regex compilation failed");
90 return false;
91 }
92 int32_t ret = regexec(®ex, str.c_str(), 0, NULL, 0);
93 if (ret == 0) {
94 regfree(®ex);
95 return true;
96 }
97 APP_LOGE("failed to perform a match");
98 regfree(®ex);
99 return false;
100 }
101
CompareIdentifiers(const std::string & a,const std::string & b)102 int32_t RouterMapHelper::CompareIdentifiers(const std::string& a, const std::string& b)
103 {
104 bool aAlnum = IsRegexMatch(a, ALNUM_PATTERN);
105 bool bAlnum = IsRegexMatch(b, ALNUM_PATTERN);
106 if (!aAlnum || !bAlnum) {
107 return 1;
108 }
109
110 bool anum = IsRegexMatch(a, NUM_PATTERN);
111 bool bnum = IsRegexMatch(b, NUM_PATTERN);
112 if (anum && bnum) {
113 auto diff = atoi(a.c_str()) - atoi(b.c_str());
114 if (diff) {
115 return diff > 0 ? 1 : -1;
116 }
117 return 0;
118 }
119
120 if (anum && !bnum) {
121 return -1;
122 }
123 if (bnum && !anum) {
124 return 1;
125 }
126 if (a < b) {
127 return -1;
128 }
129 if (a > b) {
130 return 1;
131 }
132 return 0;
133 }
134
CompareMain(const SemVer & semVer1,const SemVer & semVer2)135 int32_t RouterMapHelper::CompareMain(const SemVer &semVer1, const SemVer &semVer2)
136 {
137 auto res = CompareIdentifiers(semVer1.major, semVer2.major);
138 if (res) {
139 return res;
140 }
141 res = CompareIdentifiers(semVer1.minor, semVer2.minor);
142 if (res) {
143 return res;
144 }
145 return CompareIdentifiers(semVer1.patch, semVer2.patch);
146 }
147
ComparePre(const SemVer & semVer1,const SemVer & semVer2)148 int32_t RouterMapHelper::ComparePre(const SemVer &semVer1, const SemVer &semVer2)
149 {
150 // NOT having a prerelease is > having one
151 if (!semVer1.prerelease.empty() && semVer2.prerelease.empty()) {
152 return -1;
153 } else if (semVer1.prerelease.empty() && !semVer2.prerelease.empty()) {
154 return 1;
155 } else if (semVer1.prerelease.empty() && semVer2.prerelease.empty()) {
156 return 0;
157 }
158 size_t i = 0;
159 do {
160 if ((i >= semVer1.prerelease.size()) && (i >= semVer2.prerelease.size())) {
161 return 0;
162 } else if (i >= semVer2.prerelease.size()) {
163 return 1;
164 } else if (i >= semVer1.prerelease.size()) {
165 return -1;
166 }
167 std::string a = semVer1.prerelease[i];
168 std::string b = semVer2.prerelease[i];
169 if (a == b || !CompareIdentifiers(a, b)) {
170 continue;
171 }
172 return CompareIdentifiers(a, b);
173 } while (++i);
174 return 0;
175 }
176
Compare(const std::string & version1,const std::string & version2)177 int32_t RouterMapHelper::Compare(const std::string &version1, const std::string &version2)
178 {
179 SemVer semver1(version1);
180 SemVer semver2(version2);
181 return Compare(semver1, semver2);
182 }
183
Compare(const SemVer & semVer1,const SemVer & semVer2)184 int32_t RouterMapHelper::Compare(const SemVer &semVer1, const SemVer &semVer2)
185 {
186 if (semVer1.raw == semVer2.raw) {
187 return 0;
188 }
189 auto res = CompareMain(semVer1, semVer2);
190 return res ? res : ComparePre(semVer1, semVer2);
191 }
192 } // namespace AppExecFwk
193 } // namespace OHOS