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#ifndef JS_CONCURRENT_MODULE_COMMON_HELPER_PATH_HELPER_H
17#define JS_CONCURRENT_MODULE_COMMON_HELPER_PATH_HELPER_H
18
19#include <vector>
20#include <string>
21
22#include "native_engine/native_engine.h"
23#include "tools/log.h"
24
25namespace Commonlibrary::Concurrent::Common::Helper {
26class PathHelper {
27public:
28    static constexpr char PREFIX_BUNDLE[] = "@bundle:";
29    static constexpr char DOUBLE_POINT_TAG[] = "..";
30    static constexpr char NAME_SPACE_TAG = '@';
31    static constexpr char POINT_TAG[] = ".";
32    static constexpr char SLASH_TAG = '/';
33    static constexpr char PAG_TAG[] = "pkg_modules";
34    static constexpr char EXT_NAME_ETS[] = ".ets";
35    static constexpr char EXT_NAME_TS[] = ".ts";
36    static constexpr char EXT_NAME_JS[] = ".js";
37    static constexpr char NORMALIZED_OHMURL_TAG = '&';
38    static constexpr char PHYCICAL_FILE_PATH[] = "src/main";
39    static constexpr size_t NORMALIZED_OHMURL_ARGS_NUM = 5;
40
41    static bool CheckWorkerPath(napi_env env, std::string script, std::string fileName, bool isRelativePath)
42    {
43        std::string ohmurl = "";
44        std::string moduleName = "";
45        std::string bundleName = "";
46        if (script.find(PAG_TAG) == 0 || script.find(NAME_SPACE_TAG) != std::string::npos) {
47            HILOG_INFO("worker:: the HAR path cannot be verified");
48            return true;
49        }
50
51        bool isNormalizedOhmUrlPack = reinterpret_cast<NativeEngine*>(env)->GetIsNormalizedOhmUrlPack();
52        if (isNormalizedOhmUrlPack) {
53            return CheckNormalizedWorkerPath(env, script, fileName, isRelativePath);
54        }
55        size_t prev = script.find_first_of(SLASH_TAG);
56        while (prev == 0 && script != "") {
57            script = script.substr(1);
58            prev = script.find_first_of(SLASH_TAG);
59        }
60        if (isRelativePath) {
61            if (prev != std::string::npos) {
62                bundleName = script.substr(0, prev);
63            }
64            std::string temp = script.substr(prev + 1);
65            prev = temp.find_first_of(SLASH_TAG);
66            if (prev != std::string::npos) {
67                moduleName = temp.substr(0, prev);
68            }
69            ohmurl = PREFIX_BUNDLE + script;
70        } else {
71            if (prev != std::string::npos) {
72                moduleName = script.substr(0, prev);
73            }
74            bundleName = reinterpret_cast<NativeEngine*>(env)->GetBundleName();
75            prev = script.find_last_of(POINT_TAG);
76            if (prev != std::string::npos) {
77                script = script.substr(0, prev);
78            }
79            ohmurl = PREFIX_BUNDLE + bundleName + SLASH_TAG + script;
80        }
81        return reinterpret_cast<NativeEngine*>(env)->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmurl);
82    }
83
84    static bool CheckNormalizedWorkerPath(napi_env env, std::string script, std::string fileName, bool isRelativePath)
85    {
86        std::string ohmurl = "";
87        std::string moduleName = "";
88        std::string bundleName = "";
89        if (isRelativePath) {
90            size_t prev = fileName.find_first_of(SLASH_TAG);
91            if (prev != std::string::npos) {
92                moduleName = fileName.substr(0, prev);
93            }
94            ohmurl = script;
95        } else {
96            size_t prev = script.find_last_of(POINT_TAG);
97            if (prev != std::string::npos) {
98                script = script.substr(0, prev);
99            }
100            prev = script.find_first_of(SLASH_TAG);
101            std::string path;
102            if (prev != std::string::npos) {
103                moduleName = script.substr(0, prev);
104                path = script.substr(prev);
105            }
106            bundleName = reinterpret_cast<NativeEngine*>(env)->GetBundleName();
107            std::string pkgName = reinterpret_cast<NativeEngine*>(env)->GetPkgName(moduleName);
108            ohmurl = NORMALIZED_OHMURL_TAG + pkgName + SLASH_TAG + PHYCICAL_FILE_PATH + path + NORMALIZED_OHMURL_TAG;
109        }
110        return reinterpret_cast<NativeEngine*>(env)->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmurl);
111    }
112
113    static void ConcatFileNameForWorker(napi_env env, std::string &script, std::string &fileName, bool &isRelativePath)
114    {
115        std::string moduleName;
116        if (script.find_first_of(POINT_TAG) == 0) {
117            isRelativePath = true;
118        }
119        reinterpret_cast<NativeEngine*>(env)->GetCurrentModuleInfo(moduleName, fileName, isRelativePath);
120        if (isRelativePath) {
121            // if input is relative path, need to concat new recordName.
122            std::string recordName = moduleName;
123            size_t pos = moduleName.rfind(SLASH_TAG);
124            if (pos != std::string::npos) {
125                moduleName = moduleName.substr(0, pos + 1); // from spcific file to dir
126            }
127            script = moduleName + script;
128            script = NormalizePath(script); // remove ../ and .ets
129
130            if (recordName.at(0) == NORMALIZED_OHMURL_TAG) {
131                script.append(1, NORMALIZED_OHMURL_TAG);
132                std::vector<std::string> normalizedRes = SplitNormalizedRecordName(recordName);
133                script += normalizedRes[NORMALIZED_OHMURL_ARGS_NUM - 1];
134            }
135        } else {
136            script = moduleName + script;
137        }
138    }
139
140    static std::string NormalizePath(const std::string &entryPoint)
141    {
142        std::string res;
143        size_t prev = 0;
144        size_t curr = entryPoint.find(SLASH_TAG);
145        std::vector<std::string> elems;
146        // eliminate parent directory path
147        while (curr != std::string::npos) {
148            if (curr > prev) {
149                std::string elem = entryPoint.substr(prev, curr - prev);
150                if (elem == DOUBLE_POINT_TAG && entryPoint.at(curr) == SLASH_TAG
151                    && !elems.empty()) { // looking for xxx/../
152                    elems.pop_back();
153                } else if (elem != POINT_TAG && elem != DOUBLE_POINT_TAG) { // remove ./
154                    elems.push_back(elem);
155                }
156            }
157            prev = curr + 1;
158            curr = entryPoint.find(SLASH_TAG, prev);
159        }
160        if (prev != entryPoint.size()) {
161            elems.push_back(entryPoint.substr(prev));
162        }
163        for (auto e : elems) {
164            if (res.size() == 0 && entryPoint.at(0) != SLASH_TAG) {
165                res.append(e);
166                continue;
167            }
168            res.append(1, SLASH_TAG).append(e);
169        }
170        // remore suffix
171        size_t pos = res.rfind(POINT_TAG);
172        if (pos != std::string::npos) {
173            std::string suffix = res.substr(pos);
174            if (suffix == EXT_NAME_ETS || suffix == EXT_NAME_TS || suffix == EXT_NAME_JS) {
175                res.erase(pos, suffix.length());
176            }
177        }
178        return res;
179    }
180
181    /*
182    *  Split the recordName of the new ohmurl rule
183    *  recordName: &moduleName&bundleName&importPath&version
184    */
185    static std::vector<std::string> SplitNormalizedRecordName(const std::string &recordName)
186    {
187        std::vector<std::string> res(NORMALIZED_OHMURL_ARGS_NUM);
188        int index = NORMALIZED_OHMURL_ARGS_NUM - 1;
189        std::string temp;
190        int endIndex = static_cast<int>(recordName.size()) - 1;
191        for (int i = endIndex; i >= 0; i--) {
192            char element = recordName[i];
193            if (element == NORMALIZED_OHMURL_TAG) {
194                res[index] = temp;
195                index--;
196                temp = "";
197                continue;
198            }
199            temp = element + temp;
200        }
201        if (temp.size()) {
202            res[index] = temp;
203        }
204        return res;
205    }
206};
207} // namespace Commonlibrary::Concurrent::Common::Helper
208#endif // JS_CONCURRENT_MODULE_COMMON_HELPER_OBJECT_HELPER_H
209