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
16 #include "commonUtil.h"
17
18 #include "util/helpers.h"
19
20 namespace panda::es2panda::util {
21
Split(const std::string & str,const char delimiter)22 std::vector<std::string> Split(const std::string &str, const char delimiter)
23 {
24 std::vector<std::string> items;
25
26 size_t start = 0;
27 size_t pos = str.find(delimiter);
28 while (pos != std::string::npos) {
29 std::string item = str.substr(start, pos - start);
30 items.emplace_back(item);
31 start = pos + 1;
32 pos = str.find(delimiter, start);
33 }
34 std::string tail = str.substr(start);
35 items.emplace_back(tail);
36
37 return items;
38 }
39
GetStringByVectorElementsWithDelimiter(const std::vector<std::string> & vec,const char delimiter)40 std::string GetStringByVectorElementsWithDelimiter(const std::vector<std::string> &vec, const char delimiter)
41 {
42 std::ostringstream oss;
43 auto it = vec.begin();
44 if (it != vec.end()) {
45 oss << *it;
46 ++it;
47 }
48 for (; it != vec.end(); ++it) {
49 oss << delimiter << *it;
50 }
51 return oss.str();
52 }
53
GetPkgNameFromNormalizedImport(const std::string & normalizedImport)54 std::string GetPkgNameFromNormalizedImport(const std::string &normalizedImport)
55 {
56 std::string pkgName {};
57 size_t pos = normalizedImport.find(SLASH_TAG);
58 if (pos != std::string::npos) {
59 pkgName = normalizedImport.substr(0, pos);
60 }
61 if (normalizedImport[0] == NORMALIZED_OHMURL_PREFIX) {
62 pos = normalizedImport.find(SLASH_TAG, pos + 1);
63 if (pos != std::string::npos) {
64 pkgName = normalizedImport.substr(0, pos);
65 }
66 }
67 return pkgName;
68 }
69
GetPkgNameFromNormalizedOhmurl(const std::string & ohmurl)70 std::string GetPkgNameFromNormalizedOhmurl(const std::string &ohmurl)
71 {
72 std::string normalizedImport {};
73 std::string pkgName {};
74 auto items = Split(ohmurl, NORMALIZED_OHMURL_SEPARATOR);
75 if (items.size() <= NORMALIZED_IMPORT_POS) {
76 return pkgName;
77 }
78 normalizedImport = items[NORMALIZED_IMPORT_POS];
79 return GetPkgNameFromNormalizedImport(normalizedImport);
80 }
81
GetRecordNameFromNormalizedOhmurl(const std::string & ohmurl)82 std::string GetRecordNameFromNormalizedOhmurl(const std::string &ohmurl)
83 {
84 // format of recordName: "<bundleName>&normalizedImport&<version>"
85 std::string recordName {};
86 auto items = Split(ohmurl, NORMALIZED_OHMURL_SEPARATOR);
87
88 recordName += items[BUNDLE_NAME_POS] + NORMALIZED_OHMURL_SEPARATOR + items[NORMALIZED_IMPORT_POS] +
89 NORMALIZED_OHMURL_SEPARATOR + items[VERSION_POS];
90 return recordName;
91 }
92
IsExternalPkgNames(const std::string & ohmurl,const std::set<std::string> & externalPkgNames)93 bool IsExternalPkgNames(const std::string &ohmurl, const std::set<std::string> &externalPkgNames)
94 {
95 auto pkgName = GetPkgNameFromNormalizedOhmurl(ohmurl);
96 if (std::find(externalPkgNames.begin(), externalPkgNames.end(), pkgName) != externalPkgNames.end()) {
97 return true;
98 }
99 return false;
100 }
101
UpdatePackageVersionIfNeeded(const std::string & ohmurl,const std::map<std::string,PkgInfo> & pkgContextInfo)102 std::string UpdatePackageVersionIfNeeded(const std::string &ohmurl,
103 const std::map<std::string, PkgInfo> &pkgContextInfo)
104 {
105 // Input ohmurl format:
106 // @normalized:{N|Y}&[module name]&[bundle name]&{<package name>|<@package/name>}/{import_path}&[version]
107 // Update the version for ohmurls and return the updated ohmurl when:
108 // 1. The package name and version are specified in the CompileContextInfo file.
109 // 2. The ohmurl is an imported non-native ohmurl (starts with @normalized:N).
110 // 3. The version in the ohmurl differs from the version in the CompileContextInfo file.
111 // Return the original ohmurl otherwise.
112 if (ohmurl.find(util::NORMALIZED_OHMURL_NOT_SO) != 0) {
113 return ohmurl;
114 }
115 std::string packageName = util::GetPkgNameFromNormalizedOhmurl(ohmurl);
116 // Incorrect ohmurl format: no package name, skip version update
117 if (packageName.empty()) {
118 return ohmurl;
119 }
120 auto iter = pkgContextInfo.find(packageName);
121 if (iter == pkgContextInfo.end()) {
122 return ohmurl;
123 }
124 auto versionStart = ohmurl.rfind(util::NORMALIZED_OHMURL_SEPARATOR);
125 // Incorrect ohmurl format: no version, skip version update
126 if (versionStart == std::string::npos) {
127 return ohmurl;
128 }
129 return ohmurl.substr(0, versionStart + 1) + iter->second.version;
130 }
131
132 /**
133 * Modify the package name in the bytecode. The modifiedPkgName format is originalPkgName:targetPkgName.
134 */
UpdatePackageNameIfNeeded(const std::string & ohmurl,const std::string & modifiedPkgName)135 std::string UpdatePackageNameIfNeeded(const std::string &ohmurl, const std::string &modifiedPkgName)
136 {
137 if (ohmurl.find(util::NORMALIZED_OHMURL_NOT_SO) != 0) {
138 return ohmurl;
139 }
140 std::string packageName = util::GetPkgNameFromNormalizedOhmurl(ohmurl);
141 std::vector<std::string> pkgNames = Split(modifiedPkgName, COLON_SEPARATOR);
142 if (packageName == pkgNames[ORIGINAL_PKG_NAME_POS]) {
143 size_t pos = ohmurl.find(NORMALIZED_OHMURL_SEPARATOR + packageName) + 1;
144 std::string modified = ohmurl;
145 std::string target = pkgNames[TARGET_PKG_NAME_POS];
146 modified.replace(pos, packageName.length(), target);
147 return modified;
148 }
149 return ohmurl;
150 }
151
152 /**
153 * If a Har package is dependent of a cross-app Hsp, its ohmurl need to contain the bundleName of this cross-app Hsp.
154 * Since Har's ohmurl doesn't contain bundleName during its own compilation, the bundleName need to be added during
155 * the compilation of cross-app Hsp.
156 */
UpdateBundleNameIfNeeded(std::string & ohmurl,const std::string & bundleName,const std::set<std::string> & externalPkgNames)157 std::string UpdateBundleNameIfNeeded(std::string &ohmurl, const std::string &bundleName,
158 const std::set<std::string> &externalPkgNames)
159 {
160 // Input ohmurl format:
161 // @normalized:{N|Y}&[module name]&[bundle name]&{<package name>|<@package/name>}/{import_path}&[version]
162 if (ohmurl.find(util::NORMALIZED) != 0) {
163 return ohmurl;
164 }
165
166 std::vector<std::string> items = Split(ohmurl, NORMALIZED_OHMURL_SEPARATOR);
167 // Incorrect ohmurl format: The quantity of '&' is incorrect
168 if (items.size() <= VERSION_POS) {
169 return ohmurl;
170 }
171 /**
172 * If an ohmurl already contains [bundle name], it means its not from a Har, so there's no need to updated its
173 * [bundle name].
174 */
175 if (!items[BUNDLE_NAME_POS].empty()) {
176 return ohmurl;
177 }
178 /**
179 * The hsp package don't compile into the current abc file.
180 * Ohmurl of both Har and in-app Hsp don't contain [bundle name], need to further screen out Hsp.
181 */
182 if (IsExternalPkgNames(ohmurl, externalPkgNames)) {
183 return ohmurl;
184 }
185
186 items[BUNDLE_NAME_POS] = bundleName;
187 return GetStringByVectorElementsWithDelimiter(items, NORMALIZED_OHMURL_SEPARATOR);
188 }
189
RecordNotGeneratedFromBytecode(std::string recordName)190 bool RecordNotGeneratedFromBytecode(std::string recordName)
191 {
192 return recordName.find(util::CHAR_VERTICAL_LINE) == std::string::npos;
193 }
194
195 } // namespace panda::es2panda::util