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 
17 #include "app_log_wrapper.h"
18 #include "router_item_compare.h"
19 
20 namespace OHOS {
21 namespace AppExecFwk {
22 namespace {
23 const std::regex ALNUM_REGEX("^[a-zA-Z0-9]*$");
24 const std::regex NUM_REGEX("^[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 
CompareIdentifiers(const std::string & a,const std::string & b)85 int32_t RouterMapHelper::CompareIdentifiers(const std::string& a, const std::string& b)
86 {
87     if (!std::regex_match(a, ALNUM_REGEX) || !std::regex_match(b, ALNUM_REGEX)) {
88         return 1;
89     }
90     bool anum = std::regex_match(a, NUM_REGEX);
91     bool bnum = std::regex_match(b, NUM_REGEX);
92     if (anum && bnum) {
93         auto diff = std::stoi(a) - std::stoi(b);
94         if (diff) {
95             return diff > 0 ? 1 : -1;
96         }
97         return 0;
98     }
99 
100     if (anum && !bnum) {
101         return -1;
102     }
103     if (bnum && !anum) {
104         return 1;
105     }
106     if (a < b) {
107         return -1;
108     }
109     if (a > b) {
110         return 1;
111     }
112     return 0;
113 }
114 
CompareMain(const SemVer & semVer1,const SemVer & semVer2)115 int32_t RouterMapHelper::CompareMain(const SemVer &semVer1, const SemVer &semVer2)
116 {
117     auto res = CompareIdentifiers(semVer1.major, semVer2.major);
118     if (res) {
119         return res;
120     }
121     res = CompareIdentifiers(semVer1.minor, semVer2.minor);
122     if (res) {
123         return res;
124     }
125     return CompareIdentifiers(semVer1.patch, semVer2.patch);
126 }
127 
ComparePre(const SemVer & semVer1,const SemVer & semVer2)128 int32_t RouterMapHelper::ComparePre(const SemVer &semVer1, const SemVer &semVer2)
129 {
130     // NOT having a prerelease is > having one
131     if (!semVer1.prerelease.empty() && semVer2.prerelease.empty()) {
132         return -1;
133     } else if (semVer1.prerelease.empty() && !semVer2.prerelease.empty()) {
134         return 1;
135     } else if (semVer1.prerelease.empty() && semVer2.prerelease.empty()) {
136         return 0;
137     }
138     size_t i = 0;
139     do {
140         if ((i >= semVer1.prerelease.size()) && (i >= semVer2.prerelease.size())) {
141             return 0;
142         } else if (i >= semVer2.prerelease.size()) {
143             return 1;
144         } else if (i >= semVer1.prerelease.size()) {
145             return -1;
146         }
147         std::string a = semVer1.prerelease[i];
148         std::string b = semVer2.prerelease[i];
149         if (a == b || !CompareIdentifiers(a, b)) {
150             continue;
151         }
152         return CompareIdentifiers(a, b);
153     } while (++i);
154     return 0;
155 }
156 
Compare(const std::string & version1,const std::string & version2)157 int32_t RouterMapHelper::Compare(const std::string &version1, const std::string &version2)
158 {
159     SemVer semver1(version1);
160     SemVer semver2(version2);
161     return Compare(semver1, semver2);
162 }
163 
Compare(const SemVer & semVer1,const SemVer & semVer2)164 int32_t RouterMapHelper::Compare(const SemVer &semVer1, const SemVer &semVer2)
165 {
166     if (semVer1.raw == semVer2.raw) {
167         return 0;
168     }
169     auto res = CompareMain(semVer1, semVer2);
170     return res ? res : ComparePre(semVer1, semVer2);
171 }
172 } // namespace AppExecFwk
173 } // namespace OHOS