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 <algorithm>
19
20#include "util/helpers.h"
21
22namespace panda::es2panda::util {
23
24std::vector<std::string> Split(const std::string &str, const char delimiter)
25{
26    std::string normalizedImport {};
27    std::string pkgName {};
28    std::vector<std::string> items;
29
30    size_t start = 0;
31    size_t pos = str.find(delimiter);
32    while (pos != std::string::npos) {
33        std::string item = str.substr(start, pos - start);
34        items.emplace_back(item);
35        start = pos + 1;
36        pos = str.find(delimiter, start);
37    }
38    std::string tail = str.substr(start);
39    items.emplace_back(tail);
40
41    return items;
42}
43
44std::string GetPkgNameFromNormalizedImport(const std::string &normalizedImport)
45{
46    std::string pkgName {};
47    size_t pos = normalizedImport.find(SLASH_TAG);
48    if (pos != std::string::npos) {
49        pkgName = normalizedImport.substr(0, pos);
50    }
51    if (normalizedImport[0] == NORMALIZED_OHMURL_PREFIX) {
52        pos = normalizedImport.find(SLASH_TAG, pos + 1);
53        if (pos != std::string::npos) {
54            pkgName = normalizedImport.substr(0, pos);
55        }
56    }
57    return pkgName;
58}
59
60std::string GetPkgNameFromNormalizedOhmurl(const std::string &ohmurl)
61{
62    std::string normalizedImport {};
63    std::string pkgName {};
64    auto items = Split(ohmurl, NORMALIZED_OHMURL_SEPARATOR);
65    if (items.size() <= NORMALIZED_IMPORT_POS) {
66        return pkgName;
67    }
68    normalizedImport = items[NORMALIZED_IMPORT_POS];
69    return GetPkgNameFromNormalizedImport(normalizedImport);
70}
71
72std::string GetRecordNameFromNormalizedOhmurl(const std::string &ohmurl)
73{
74    // format of recordName: "<bundleName>&normalizedImport&<version>"
75    std::string recordName {};
76    auto items = Split(ohmurl, NORMALIZED_OHMURL_SEPARATOR);
77
78    recordName += items[BUNDLE_NAME_POS] + NORMALIZED_OHMURL_SEPARATOR + items[NORMALIZED_IMPORT_POS] +
79        NORMALIZED_OHMURL_SEPARATOR + items[VERSION_POS];
80    return recordName;
81}
82
83bool IsExternalPkgNames(const std::string &ohmurl, const std::set<std::string> &externalPkgNames)
84{
85    auto pkgName = GetPkgNameFromNormalizedOhmurl(ohmurl);
86    if (std::find(externalPkgNames.begin(), externalPkgNames.end(), pkgName) != externalPkgNames.end()) {
87        return true;
88    }
89    return false;
90}
91
92std::string UpdatePackageVersionIfNeeded(const std::string &ohmurl,
93                                         const std::unordered_map<std::string, PkgInfo> &pkgContextInfo)
94{
95    // Input ohmurl format:
96    // @normalized:{N|Y}&[module name]&[bundle name]&{<package name>|<@package/name>}/{import_path}&[version]
97    // Update the version for ohmurls and return the updated ohmurl when:
98    // 1. The package name and version are specified in the CompileContextInfo file.
99    // 2. The ohmurl is an imported non-native ohmurl (starts with @normalized:N).
100    // 3. The version in the ohmurl differs from the version in the CompileContextInfo file.
101    // Return the original ohmurl otherwise.
102    if (ohmurl.find(util::NORMALIZED_OHMURL_NOT_SO) != 0) {
103        return ohmurl;
104    }
105    std::string packageName = util::GetPkgNameFromNormalizedOhmurl(ohmurl);
106    // Incorrect ohmurl format: no package name, skip version update
107    if (packageName.empty()) {
108        return ohmurl;
109    }
110    auto iter = pkgContextInfo.find(packageName);
111    if (iter == pkgContextInfo.end()) {
112        return ohmurl;
113    }
114    auto versionStart = ohmurl.rfind(util::NORMALIZED_OHMURL_SEPARATOR);
115    // Incorrect ohmurl format: no version, skip version update
116    if (versionStart == std::string::npos) {
117        return ohmurl;
118    }
119    return ohmurl.substr(0, versionStart + 1) + iter->second.version;
120}
121
122bool RecordNotGeneratedFromBytecode(std::string recordName)
123{
124    return recordName.find(util::CHAR_VERTICAL_LINE) == std::string::npos;
125}
126
127} // namespace panda::es2panda::util