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#ifndef ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H
16#define ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H
17
18#include "ecmascript/base/path_helper.h"
19
20#include "ecmascript/compiler/aot_file/aot_file_manager.h"
21#include "ecmascript/base/string_helper.h"
22#include "ecmascript/ecma_macros.h"
23#include "ecmascript/ecma_string.h"
24#include "ecmascript/ecma_vm.h"
25#include "ecmascript/global_env.h"
26#include "ecmascript/js_tagged_value-inl.h"
27#include "ecmascript/jspandafile/js_pandafile.h"
28/*
29 * Intra-application cross hap:
30 * baseFileName = 'data/storage/el1/bundle/moduleName/ets/modules.abc';
31 * cross-application:
32 * baseFileName = 'data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc';
33 * recordName = bundleName/moduleName/xxx(entry)/xxx(ets)/xxx(pages)/xxx  specific abc file
34 *
35 * ohmUrl: It's an index information that can uniquely identify module files.
36 * Current ohmUrl has the following five different prefixs:
37 * 1. @bundle:... Identify OpenHarmony modules.
38 *    {project_path}\entry\src\main\ets\pages\Index --> @bundle:bundleName/moduleName/ets/pages/Index
39 *    @namespace: needs to add when import local har or ohosTest import entry file.
40 *    {project_path}\namespace\src\main\ets\pages\Index --> @bundle:bundleName/moduleName@namespace/ets/pages/Index
41 *
42 * 2. @package:... Identify open source third party modules.
43 *    {project_path}\node_modules.ohpm\pkgName\oh_modules\pkgName\xxx\xxx
44 *    --> @package:pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx
45 *
46 * 3. @app:... Identify c++ modules in application.
47 *    libxxx.so --> @app:bundleName/moduleName/xxx
48 *
49 * 4. @native:... Identify system builtin modules.
50 *    system.app --> @native:system.app
51 *
52 * 5. @ohos:... Identify ohos builtin modules.
53 *    @ohos:hilog --> @ohos:hilog
54 */
55
56namespace panda::ecmascript {
57using PathHelper = base::PathHelper;
58using StringHelper = base::StringHelper;
59
60enum ValidateFilePath { ABC, ETS_MODULES };
61
62class ModulePathHelper {
63public:
64    static constexpr char EXT_NAME_ABC[] = ".abc";
65    static constexpr char EXT_NAME_ETS[] = ".ets";
66    static constexpr char EXT_NAME_TS[] = ".ts";
67    static constexpr char EXT_NAME_JS[] = ".js";
68    static constexpr char EXT_NAME_JSON[] = ".json";
69    static constexpr char EXT_NAME_Z_SO[] = ".z.so";
70    static constexpr char EXT_NAME_D_TS[] = ".d.ts";
71    static constexpr char EXT_NAME_MJS[] = ".mjs";
72    static constexpr char EXT_NAME_HQF[] = ".hqf";
73    static constexpr char PREFIX_NORMALIZED[] = "@normalized:";
74    static constexpr char PREFIX_NORMALIZED_SO[] = "@normalized:Y";
75    static constexpr char PREFIX_NORMALIZED_NOT_SO[] = "@normalized:N";
76    static constexpr char PREFIX_BUNDLE[] = "@bundle:";
77    static constexpr char PREFIX_MODULE[] = "@module:";
78    static constexpr char PREFIX_PACKAGE[] = "@package:";
79    static constexpr char PREFIX_ETS[] = "ets/";
80    static constexpr char PREFIX_LIB[] = "lib";
81    static constexpr char REQUIRE_NAITVE_MODULE_PREFIX[] = "@native:";
82    static constexpr char REQUIRE_NAPI_OHOS_PREFIX[] = "@ohos:";
83    static constexpr char REQUIRE_NAPI_APP_PREFIX[] = "@app:";
84    static constexpr char RAW_ARKUIX_PREFIX[] = "@arkui-x.";
85    static constexpr char NPM_PATH_SEGMENT[] = "node_modules";
86    static constexpr char PACKAGE_PATH_SEGMENT[] = "pkg_modules";
87    static constexpr char PACKAGE_ENTRY_FILE[] = "/index";
88    static constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
89    static constexpr char MERGE_ABC_ETS_MODULES[] = "/ets/modules.abc";
90    static constexpr char ABC[] = ".abc";
91    static constexpr char MODULE_DEFAULE_ETS[] = "/ets/";
92    static constexpr char BUNDLE_SUB_INSTALL_PATH[] = "/data/storage/el1/";
93    static constexpr char PREVIEW_OF_ACROSS_HAP_FLAG[] = "[preview]";
94    static constexpr char PREVIER_TEST_DIR[] = ".test";
95    static constexpr char PHYCICAL_FILE_PATH[] = "/src/main";
96    static constexpr char VMA_NAME_ARKTS_CODE[] = "ArkTS Code";
97    static constexpr char ENTRY_MAIN_FUNCTION[] = "_GLOBAL::func_main_0";
98    static constexpr char TRUE_FLAG[] = "true";
99
100    static constexpr size_t MAX_PACKAGE_LEVEL = 1;
101    static constexpr size_t SEGMENTS_LIMIT_TWO = 2;
102    static constexpr size_t EXT_NAME_ABC_LEN = 4;
103    static constexpr size_t EXT_NAME_ETS_LEN = 4;
104    static constexpr size_t EXT_NAME_TS_LEN = 3;
105    static constexpr size_t EXT_NAME_JS_LEN = 3;
106    static constexpr size_t EXT_NAME_JSON_LEN = 5;
107    static constexpr size_t PREFIX_BUNDLE_LEN = 8;
108    static constexpr size_t PREFIX_MODULE_LEN = 8;
109    static constexpr size_t PREFIX_PACKAGE_LEN = 9;
110    static constexpr size_t PACKAGE_PATH_SEGMENT_LEN = 11;
111    static constexpr size_t NATIVE_PREFIX_SIZE = 8;
112    static constexpr size_t OHOS_PREFIX_SIZE = 6;
113    static constexpr size_t APP_PREFIX_SIZE = 5;
114    static constexpr size_t BUNDLE_INSTALL_PATH_LEN = 25;
115    static constexpr size_t PHYCICAL_FILE_PATH_LEN = 10;
116    static constexpr size_t NORMALIZED_OHMURL_ARGS_NUM = 5;
117    static constexpr size_t NORMALIZED_MODULE_NAME_INDEX = 1;
118    static constexpr size_t NORMALIZED_BUNDLE_NAME_INDEX = 2;
119    static constexpr size_t NORMALIZED_IMPORT_PATH_INDEX = 3;
120    static constexpr size_t NORMALIZED_VERSION_INDEX = 4;
121    static constexpr size_t CURRENT_DIREATORY_TAG_LEN = 2;
122    static constexpr size_t SO_PREFIX_LEN = 3;
123    static constexpr size_t SO_SUFFIX_LEN = 3;
124
125    static constexpr size_t PKGINFO_PACKAGE_NAME_INDEX = 1;
126    static constexpr size_t PKGINFO_BUDNLE_NAME_INDEX = 3;
127    static constexpr size_t PKGINFO_MODULE_NAME_INDEX = 5;
128    static constexpr size_t PKGINFO_VERSION_INDEX = 7;
129    static constexpr size_t PKGINFO_ENTRY_PATH_INDEX = 9;
130    static constexpr size_t PKGINFO_IS_SO_INDEX = 11;
131
132    static CString PUBLIC_API ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
133                                                      CString &baseFileName, CString recordName, CString requestName);
134    static void ParseAbcPathAndOhmUrl(EcmaVM *vm, const CString &inputFileName, CString &outBaseFileName,
135                                      CString &outEntryPoint);
136    static CString ConcatUnifiedOhmUrl(const CString &bundleName, const CString &pkgname, const CString &entryPath,
137                                       const CString &path, const CString &version);
138    static CString ConcatUnifiedOhmUrl(const CString &bundleName, const CString &normalizedpath,
139        const CString &version);
140    static CString ConcatPreviewTestUnifiedOhmUrl(const CString &bundleName, const CString &pkgname,
141        const CString &path, const CString &version);
142    static CString ConcatHspFileNameCrossBundle(const CString &bundleName, const CString &moduleName);
143    static CString ConcatHspFileName(const CString &moduleName);
144    static CString TransformToNormalizedOhmUrl(EcmaVM *vm, const CString &inputFileName, const CString &baseFileName,
145        const CString &oldEntryPoint);
146    static CString ParseUrl(EcmaVM *vm, const CString &recordName);
147    static CString ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile,
148        [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName);
149    static CString ParseNormalizedOhmUrl(JSThread *thread, CString &baseFileName, const CString &recordName,
150                                         CString requestName);
151    static CString MakeNewRecord(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName,
152                                 const CString &recordName, const CString &requestName);
153    static CString FindOhpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &ohpmPath,
154                                      const CString &requestName);
155    static CString FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile, const CString &requestName,
156                                                      const CString &recordName);
157    static CString ParseOhpmPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
158                                    const CString &requestName);
159    static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
160                                          const CString &requestName, const CString &packagePath);
161    static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
162                                          const CString &requestName);
163    static void ResolveCurrentPath(CString &dirPath, CString &fileName, const JSPandaFile *jsPandaFile);
164    static CString FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint);
165    static CString FindPackageInTopLevel(const JSPandaFile *jsPandaFile, const CString &requestName,
166                                         const CString &packagePath);
167    static bool IsImportFile(const CString &moduleRequestName);
168    static CString RemoveSuffix(const CString &requestName);
169    static bool NeedTranstale(const CString &requestName);
170    static bool NeedTranslateToNormalized(const CString &requestName);
171    static void TranstaleExpressionInput(const JSPandaFile *jsPandaFile, CString &requestPath);
172    static CString GetModuleNameWithBaseFile(const CString &baseFileName);
173    static CString TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile,
174                                                   CString &baseFileName, const CString &requestName);
175    static void ParseCrossModuleFile(const JSPandaFile *jsPandaFile, CString &requestPath);
176    static CString ReformatPath(CString requestName);
177    static CString TranslateExpressionToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
178                                                   [[maybe_unused]] CString &baseFileName, const CString &recordName,
179                                                   CString &requestPath);
180    static CVector<CString> GetPkgContextInfoListElements(EcmaVM *vm, CString &moduleName,
181                                                          CString &packageName);
182    static CString TranslateNapiFileRequestPath(JSThread *thread, const CString &modulePath,
183                                                const CString &requestName);
184    static CVector<CString> SplitNormalizedOhmurl(const CString &ohmurl);
185    static CString ConcatImportFileNormalizedOhmurl(const CString &recordPath, const CString &requestName,
186                                                    const CString &version = "");
187    static CString ConcatNativeSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
188                                                  const CString &pkgName, const CString &version);
189    static CString ConcatNotSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
190                                               const CString &pkgName, const CString &entryPath,
191                                               const CString &version);
192    static CString ConcatMergeFileNameToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
193                                                   CString &baseFileName, const CString &recordName,
194                                                   CString requestName);
195    static CVector<CString> SplitNormalizedRecordName(const CString &recordName);
196    static CString ConcatImportFileNormalizedOhmurlWithRecordName(JSThread *thread, const JSPandaFile *jsPandaFile,
197                                                                  CString &baseFileName, const CString &recordName,
198                                                                  const CString &requestName);
199    static void ConcatOtherNormalizedOhmurl(EcmaVM *vm, const JSPandaFile *jsPandaFile,
200                                            [[maybe_unused]] CString &baseFileName, CString &requestPath);
201    static CString ConcatNormalizedOhmurlWithData(CVector<CString> &data, CString &pkgName, CString &entryPath);
202    static CString GetBundleNameWithRecordName(EcmaVM *vm, const CString &recordName);
203    static CString Utf8ConvertToString(JSTaggedValue str);
204
205    static CString ParseFileNameToVMAName(const CString &filename);
206    static CString ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM *vm, size_t filePathPos, CString &moduleName,
207                                                           const CString &requestPath);
208    static bool IsOhmUrl(const CString &str);
209    static bool CheckAndGetRecordName(JSThread *thread, const CString &ohmUrl, CString &recordName);
210    static bool ValidateAbcPath(const CString &baseFileName, ValidateFilePath checkMode);
211    /*
212     * Before: /data/storage/el1/bundle/moduleName/ets/modules.abc
213     * After:  bundle/moduleName
214     */
215    inline static std::string ParseHapPath(const CString &baseFileName)
216    {
217        CString bundleSubInstallName(BUNDLE_SUB_INSTALL_PATH);
218        size_t startStrLen = bundleSubInstallName.length();
219        if (baseFileName.length() > startStrLen && baseFileName.compare(0, startStrLen, bundleSubInstallName) == 0) {
220            CString hapPath = baseFileName.substr(startStrLen);
221            size_t pos = hapPath.find(MERGE_ABC_ETS_MODULES);
222            if (pos != CString::npos) {
223                return hapPath.substr(0, pos).c_str();
224            }
225        }
226        return std::string();
227    }
228
229    /*
230     * Before: xxx
231     * After:  xxx || xxx/index
232     */
233    inline static CString ConfirmLoadingIndexOrNot(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
234    {
235        CString entryPoint = packageEntryPoint;
236        if (jsPandaFile->HasRecord(entryPoint)) {
237            return entryPoint;
238        }
239        // Possible import directory
240        entryPoint += PACKAGE_ENTRY_FILE;
241        entryPoint = PathHelper::NormalizePath(entryPoint);
242        if (jsPandaFile->HasRecord(entryPoint)) {
243            return entryPoint;
244        }
245        return CString();
246    }
247
248    inline static bool IsNativeModuleRequest(const CString &requestName)
249    {
250        if (requestName[0] != PathHelper::NAME_SPACE_TAG) {
251            return false;
252        }
253        if (StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAPI_OHOS_PREFIX) ||
254            StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAPI_APP_PREFIX) ||
255            StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) {
256            return true;
257        }
258        return false;
259    }
260
261    /*
262     * Before: bundleName/moduleName/ets/xxx/xxx
263     * After:  moduleName
264     */
265    inline static CString GetModuleName(const CString recordName)
266    {
267        size_t pos1 = recordName.find(PathHelper::SLASH_TAG);
268        if (pos1 != CString::npos) {
269            pos1++;
270            size_t pos2 = recordName.find(PathHelper::SLASH_TAG, pos1);
271            if (pos2 != CString::npos) {
272                CString moduleName = recordName.substr(pos1, pos2 - pos1);
273                PathHelper::DeleteNamespace(moduleName);
274                return moduleName;
275            }
276        }
277        return CString();
278    }
279
280    /*
281     * Before: &moduleName/src/xxx
282     * After:  moduleName
283     */
284    inline static CString GetModuleNameWithNormalizedName(const CString recordName)
285    {
286        size_t pos1 = recordName.find(PathHelper::NORMALIZED_OHMURL_TAG);
287        if (pos1 != CString::npos) {
288            pos1++;
289            size_t pos2 = recordName.find(PathHelper::SLASH_TAG, pos1);
290            if (pos2 != CString::npos) {
291                CString moduleName = recordName.substr(pos1, pos2 - pos1);
292                return moduleName;
293            }
294        }
295        return CString();
296    }
297
298    /*
299     * Before: bundleName/moduleName
300     * After:  moduleName
301     */
302    inline static CString GetModuleNameWithPath(const CString modulePath)
303    {
304        size_t pos1 = modulePath.find(PathHelper::SLASH_TAG);
305        if (pos1 != CString::npos) {
306            pos1++;
307            return modulePath.substr(pos1, modulePath.size() - pos1 + 1);
308        }
309        return CString();
310    }
311    /*
312     * Before: @xxx.
313     * After:  @xxx:
314     */
315    inline static bool ChangeTag(CString &path)
316    {
317        if (path[0] == PathHelper::NAME_SPACE_TAG) {
318            size_t pos = path.find(PathHelper::POINT_TAG);
319            if (pos != CString::npos) {
320                path.replace(pos, 1, PathHelper::COLON_TAG); // 1: length
321                return true;
322            }
323        }
324        return false;
325    }
326
327    /*
328     * Before: moduleName
329     * After:  data/storage/el1/bundle/moduleName/ets/modules.abc
330     */
331    inline static CString ConcatPandaFilePath(const CString &moduleName)
332    {
333        if (moduleName.size() == 0) {
334            return CString();
335        }
336        return BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
337    }
338
339    inline static CString GetBundleNameFromNormalized(const EcmaVM *vm, const CString &moduleName)
340    {
341        CVector<CString> res = SplitNormalizedOhmurl(moduleName);
342        if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
343            LOG_FULL(ERROR) << "GetBundleNameFromNormalized Invalid normalized ohmurl";
344            return "";
345        }
346        CString bundleName = res[NORMALIZED_BUNDLE_NAME_INDEX];
347        if (bundleName.size() == 0) {
348            return vm->GetBundleName();
349        }
350        return bundleName;
351    }
352
353    inline static CString GetNormalizedPathFromOhmUrl(const CString &moduleName)
354    {
355        CVector<CString> res = SplitNormalizedOhmurl(moduleName);
356        if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
357            LOG_FULL(ERROR) << "GetNormalizedPathFromOhmUrl Invalid normalized ohmurl";
358            return "";
359        }
360        CString soName = res[NORMALIZED_IMPORT_PATH_INDEX];
361        // Delete the prefix "lib" and suffix ".so".
362        soName = soName.substr(SO_PREFIX_LEN, soName.size() - SO_PREFIX_LEN - SO_SUFFIX_LEN);
363        return soName;
364    }
365};
366} // namespace panda::ecmascript
367#endif // ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H