• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ecmascript/module/module_path_helper.h"
16 
17 #include "ecmascript/platform/module.h"
18 
19 namespace panda::ecmascript {
20 /*
21  * This function use recordName, requestName to get baseFileName and entryPoint.
22  * The prefiex of "@bundle", "@package" represents the old path encoding format, while "@normalized" represents the
23  * unified format.
24  */
ConcatFileNameWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)25 CString ModulePathHelper::ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
26     CString &baseFileName, const CString &recordName, const CString &requestName)
27 {
28     if (StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED_NOT_CROSS_HAP_FILE)) {
29         return requestName.substr(PREFIX_NORMALIZED_LEN);
30     }
31     if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE)) {
32         return ParsePrefixBundle(thread, jsPandaFile, baseFileName, requestName, recordName);
33     }
34     if (StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
35         return requestName.substr(PREFIX_PACKAGE_LEN);
36     }
37     if (thread->GetEcmaVM()->IsNormalizedOhmUrlPack()) {
38         return ConcatMergeFileNameToNormalized(thread, jsPandaFile, baseFileName, recordName, requestName);
39     }
40     if (IsImportFile(requestName)) {
41         // this branch save for require/dynamic import/old version sdk
42         // load a relative pathName.
43         // requestName: ./ || ./xxx/xxx.js || ../xxx/xxx.js || ./xxx/xxx
44         return MakeNewRecord(thread, jsPandaFile, baseFileName, recordName, requestName);
45     }
46     if (StringHelper::StringStartWith(requestName, PREFIX_ETS)) {
47         CString entryPoint = TranslateExpressionInputWithEts(thread, jsPandaFile, baseFileName, requestName);
48         if (entryPoint.empty()) {
49             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
50         }
51         return entryPoint;
52     }
53     // this branch save for require/dynamic import/old version sdk
54     // requestName: requestPkgName
55     CString entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
56     if (entryPoint.empty()) {
57         THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
58     }
59     return entryPoint;
60 }
61 
ConcatMergeFileNameToNormalized(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,CString requestName)62 CString ModulePathHelper::ConcatMergeFileNameToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
63     CString &baseFileName, const CString &recordName, CString requestName)
64 {
65     if (StringHelper::StringStartWith(requestName, PathHelper::NORMALIZED_OHMURL_TAG)) {
66         return requestName;
67     } else if (IsImportFile(requestName)) {
68         if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
69             return MakeNewRecord(thread, jsPandaFile, baseFileName, recordName, requestName);
70         }
71         // this branch save for import "xxx.js" in npm
72         CString inputPath = requestName;
73         CString entryPoint = ConcatImportFileNormalizedOhmurlWithRecordName(thread, jsPandaFile, baseFileName,
74             recordName, requestName);
75         if (entryPoint.empty()) {
76             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestName);
77         }
78         return entryPoint;
79     } else {
80         // this branch save for require npm
81         TranslateExpressionToNormalized(thread, jsPandaFile, baseFileName, recordName, requestName);
82     }
83     return ParseNormalizedOhmUrl(thread, baseFileName, recordName, requestName);
84 }
85 
86 /*
87  * Before: requestName: ../xxx1/xxx2 || ./xxx1
88  * After:  1.&entryPath&version
89  *         2.bundleName&entryPath&version
90  */
ConcatImportFileNormalizedOhmurlWithRecordName(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)91 CString ModulePathHelper::ConcatImportFileNormalizedOhmurlWithRecordName(JSThread *thread,
92     const JSPandaFile *jsPandaFile, CString &baseFileName, const CString &recordName, const CString &requestName)
93 {
94     CString entryPoint;
95     CVector<CString> res = SplitNormalizedRecordName(recordName);
96     CString path = res[NORMALIZED_BUNDLE_NAME_INDEX];
97     path += PathHelper::NORMALIZED_OHMURL_TAG;
98     path += res[NORMALIZED_IMPORT_PATH_INDEX];
99     const CString& version = res[NORMALIZED_VERSION_INDEX];
100     CString moduleRequestName = requestName;
101     moduleRequestName = RemoveSuffix(moduleRequestName);
102     size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
103     if (pos == 0) {
104         moduleRequestName = moduleRequestName.substr(CURRENT_DIREATORY_TAG_LEN);
105     }
106     pos = path.rfind(PathHelper::SLASH_TAG);
107     if (pos != CString::npos) {
108         entryPoint = path.substr(0, pos + 1) + moduleRequestName;
109     } else {
110         entryPoint = moduleRequestName;
111     }
112     entryPoint = PathHelper::NormalizePath(entryPoint);
113     moduleRequestName = ConcatImportFileNormalizedOhmurl(entryPoint, "", version);
114     if (jsPandaFile->HasRecord(moduleRequestName)) {
115         return moduleRequestName;
116     }
117     // requestName may be a folder
118     entryPoint += PACKAGE_ENTRY_FILE;
119     entryPoint = PathHelper::NormalizePath(entryPoint);
120     moduleRequestName = ConcatImportFileNormalizedOhmurl(entryPoint, "", version);
121     if (jsPandaFile->HasRecord(moduleRequestName)) {
122         return moduleRequestName;
123     }
124 
125     // requestName may be a packageName
126     moduleRequestName = requestName;
127     ConcatOtherNormalizedOhmurl(thread->GetEcmaVM(), jsPandaFile, baseFileName, moduleRequestName);
128     moduleRequestName = ParseNormalizedOhmUrl(thread, baseFileName, recordName, moduleRequestName);
129     if (jsPandaFile->HasRecord(moduleRequestName)) {
130         return moduleRequestName;
131     }
132     return {};
133 }
134 
ReformatPath(const CString & requestName)135 CString ModulePathHelper::ReformatPath(const CString& requestName)
136 {
137     CString normalizeStr;
138     if (StringHelper::StringStartWith(requestName, PACKAGE_PATH_SEGMENT) ||
139         StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
140         auto pos = requestName.rfind(PACKAGE_PATH_SEGMENT);
141         ASSERT(pos != CString::npos);
142         normalizeStr = requestName.substr(pos + PACKAGE_PATH_SEGMENT_LEN);
143     } else if (StringHelper::StringStartWith(requestName, REQUIRE_NAPI_APP_PREFIX)) {
144         auto pos = requestName.find(PathHelper::SLASH_TAG);
145         pos = requestName.find(PathHelper::SLASH_TAG, pos + 1);
146         ASSERT(pos != CString::npos);
147         normalizeStr = requestName.substr(pos + 1);
148     } else {
149         normalizeStr = requestName;
150     }
151     return normalizeStr;
152 }
153 
154 /*
155  * Before: inputFileName: 1. /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
156                           2. @bundle:bundleName/moduleName/ets/xxx/xxx.abc
157                           3. moduleName/ets/xxx/xxx.abc
158                           4. .test/xxx/xxx.abc
159                           5. xxx/xxx.abc
160  * After:  outBaseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
161  *         outEntryPoint: bundleName/moduleName/ets/xxx/xxx
162  */
ParseAbcPathAndOhmUrl(EcmaVM * vm,const CString & inputFileName,CString & outBaseFileName,CString & outEntryPoint)163 void ModulePathHelper::ParseAbcPathAndOhmUrl(EcmaVM *vm, const CString &inputFileName,
164     CString &outBaseFileName, CString &outEntryPoint)
165 {
166     size_t pos = CString::npos;
167     if (inputFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
168         inputFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
169         pos = BUNDLE_INSTALL_PATH_LEN;
170     }
171     if (pos != CString::npos) {
172         // inputFileName: /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
173         pos = inputFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
174         if (pos == CString::npos) { // LCOV_EXCL_BR_LINE
175             LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
176         }
177         CString moduleName = inputFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
178         PathHelper::DeleteNamespace(moduleName);
179         outBaseFileName = base::ConcatToCString(BUNDLE_INSTALL_PATH, moduleName, MERGE_ABC_ETS_MODULES);
180         outEntryPoint = base::ConcatToCString(vm->GetBundleName(), PathHelper::SLASH_TAG,
181                                               inputFileName.substr(BUNDLE_INSTALL_PATH_LEN));
182     } else {
183         // Temporarily handle the relative path sent by arkui
184         // inputFileName: @bundle:bundleName/moduleName/ets/xxx/xxx.abc
185         if (StringHelper::StringStartWith(inputFileName, PREFIX_BUNDLE)) {
186             outEntryPoint = inputFileName.substr(PREFIX_BUNDLE_LEN);
187             outBaseFileName = ParseUrl(vm, outEntryPoint);
188         } else {
189             outEntryPoint = GetOutEntryPoint(vm, inputFileName);
190         }
191     }
192     if (StringHelper::StringEndWith(outEntryPoint, EXT_NAME_ABC)) {
193         outEntryPoint.erase(outEntryPoint.length() - EXT_NAME_ABC_LEN, EXT_NAME_ABC_LEN);
194     }
195     if (vm->IsNormalizedOhmUrlPack()) {
196         outEntryPoint = TransformToNormalizedOhmUrl(vm, inputFileName, outBaseFileName, outEntryPoint);
197     }
198 }
199 
200 // Unified ohmUrl used be cached: [<bundle name>?]&<pkg name + /src/main + path>&[<version>?]
ConcatUnifiedOhmUrl(const CString & bundleName,const CString & pkgname,const CString & entryPath,const CString & path,const CString & version)201 CString ModulePathHelper::ConcatUnifiedOhmUrl(const CString &bundleName, const CString &pkgname,
202     const CString &entryPath, const CString &path, const CString &version)
203 {
204     if (!entryPath.empty()) {
205         // entryPath is src/xxx/
206         return base::ConcatToCString(bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgname, PathHelper::SLASH_TAG,
207                                      entryPath, path, PathHelper::NORMALIZED_OHMURL_TAG, version);
208     }
209     return base::ConcatToCString(bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgname, PHYCICAL_FILE_PATH.data(),
210         path, PathHelper::NORMALIZED_OHMURL_TAG, version);
211 }
212 
ConcatUnifiedOhmUrl(const CString & bundleName,const CString & normalizedpath,const CString & version)213 CString ModulePathHelper::ConcatUnifiedOhmUrl(const CString &bundleName, const CString &normalizedpath,
214     const CString &version)
215 {
216     return base::ConcatToCString(bundleName, PathHelper::NORMALIZED_OHMURL_TAG, normalizedpath,
217                                  PathHelper::NORMALIZED_OHMURL_TAG, version);
218 }
219 
ConcatPreviewTestUnifiedOhmUrl(const CString & bundleName,const CString & pkgname,const CString & path,const CString & version)220 CString ModulePathHelper::ConcatPreviewTestUnifiedOhmUrl(const CString &bundleName, const CString &pkgname,
221     const CString &path, const CString &version)
222 {
223     return base::ConcatToCString(bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgname, path,
224                                  PathHelper::NORMALIZED_OHMURL_TAG, version);
225 }
226 
ConcatHspFileNameCrossBundle(const CString & bundleName,const CString & moduleName)227 CString ModulePathHelper::ConcatHspFileNameCrossBundle(const CString &bundleName, const CString &moduleName)
228 {
229     return base::ConcatToCString(BUNDLE_INSTALL_PATH, bundleName, PathHelper::SLASH_TAG, moduleName,
230                                  PathHelper::SLASH_TAG, moduleName, MERGE_ABC_ETS_MODULES);
231 }
232 
ConcatHspFileName(const CString & moduleName)233 CString ModulePathHelper::ConcatHspFileName(const CString &moduleName)
234 {
235     return base::ConcatToCString(BUNDLE_INSTALL_PATH, moduleName, MERGE_ABC_ETS_MODULES);
236 }
237 
ThrowInvalidOhmurlError(EcmaVM * vm,const CString & oldEntryPoint)238 CString ModulePathHelper::ThrowInvalidOhmurlError(EcmaVM *vm, const CString &oldEntryPoint)
239 {
240     CString errorMsg = "TransformToNormalizedOhmUrl Invalid Ohmurl: " + oldEntryPoint + ", please check.";
241     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(vm->GetJSThread(), ErrorType::SYNTAX_ERROR, errorMsg.c_str(),
242         oldEntryPoint);
243 }
244 
TransformToNormalizedOhmUrl(EcmaVM * vm,const CString & inputFileName,const CString & baseFileName,const CString & oldEntryPoint)245 CString ModulePathHelper::TransformToNormalizedOhmUrl(EcmaVM *vm, const CString &inputFileName,
246     const CString &baseFileName, const CString &oldEntryPoint)
247 {
248     if (oldEntryPoint == ENTRY_MAIN_FUNCTION ||
249         StringHelper::StringStartWith(oldEntryPoint, PathHelper::NORMALIZED_OHMURL_TAG)) {
250         return oldEntryPoint;
251     }
252     LOG_ECMA(DEBUG) << "TransformToNormalizedOhmUrl inputFileName: " << inputFileName << " oldEntryPoint: " <<
253         oldEntryPoint;
254     size_t pos = oldEntryPoint.find(PathHelper::SLASH_TAG);
255     if (pos == CString::npos) {
256         return ThrowInvalidOhmurlError(vm, oldEntryPoint);
257     }
258     size_t pathPos = oldEntryPoint.find(PathHelper::SLASH_TAG, pos + 1);
259     if (pathPos == CString::npos) {
260         return ThrowInvalidOhmurlError(vm, oldEntryPoint);
261     }
262     CString path = oldEntryPoint.substr(pathPos);
263     CString moduleName = oldEntryPoint.substr(pos + 1, pathPos - pos - 1);
264     if (moduleName.find(PathHelper::NAME_SPACE_TAG) != CString::npos) {
265         moduleName = PathHelper::GetHarName(moduleName);
266     }
267     CString pkgname = vm->GetPkgName(moduleName);
268     CString currentModuleName = GetModuleNameWithBaseFile(baseFileName);
269     if (currentModuleName.empty()) {
270         currentModuleName = moduleName;
271     }
272     CVector<CString> data = GetPkgContextInfoListElements(vm, currentModuleName, pkgname);
273     if (data.empty()) {
274         return oldEntryPoint;
275     }
276     const CString &entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
277     const CString &version = data[PKGINFO_VERSION_INDEX];
278     const CString &bundleName = data[PKGINFO_BUDNLE_NAME_INDEX];
279     // If the subPath starts with '.test', it is a preview test, no need to splice the entry path.
280     CString subPath = oldEntryPoint.substr(pathPos + 1);
281     if (StringHelper::StringStartWith(subPath, PREVIER_TEST_DIR)) {
282         return ConcatPreviewTestUnifiedOhmUrl(bundleName, pkgname, path, version);
283     }
284     // When the entry path ends with a slash (/), use the entry path to concatenate ohmurl.
285     if (!entryPath.empty() && StringHelper::StringEndWith(entryPath, PathHelper::SLASH_TAG)) {
286         size_t endPos = entryPath.rfind(PathHelper::SLASH_TAG);
287         CString subEntryPath = entryPath.substr(0, endPos);
288         return ConcatUnifiedOhmUrl(bundleName, pkgname, subEntryPath, path, version);
289     }
290     // entryPath is empty.
291     return ConcatUnifiedOhmUrl(bundleName, pkgname, "", path, version);
292 }
293 
294 /*
295  * Before: recordName: bundleName/moduleName@namespace/xxx/xxx.abc
296  * After: Intra-application cross hap:   /data/storage/el1/bundle/bundleName/ets/modules.abc
297  *        Cross-application:             /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
298  */
ParseUrl(EcmaVM * vm,const CString & recordName)299 CString ModulePathHelper::ParseUrl(EcmaVM *vm, const CString &recordName)
300 {
301     CVector<CString> vec;
302     StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
303     if (vec.size() < SEGMENTS_LIMIT_TWO) {
304         LOG_ECMA(DEBUG) << "ParseUrl SplitString filed, please check Url" << recordName;
305         return {};
306     }
307     CString bundleName = vec[0];
308     CString moduleName = vec[1];
309     PathHelper::DeleteNamespace(moduleName);
310 
311     CString baseFileName;
312     if (bundleName != vm->GetBundleName()) {
313         // Cross-application
314         baseFileName = base::ConcatToCString(BUNDLE_INSTALL_PATH, bundleName, PathHelper::SLASH_TAG, moduleName,
315             PathHelper::SLASH_TAG, moduleName, MERGE_ABC_ETS_MODULES);
316     } else {
317         // Intra-application cross hap
318         baseFileName = base::ConcatToCString(BUNDLE_INSTALL_PATH, moduleName, MERGE_ABC_ETS_MODULES);
319     }
320     return baseFileName;
321 }
322 
323 /*
324  * Before: moduleRequestName: @bundle:bundleName/moduleName@namespace/ets/xxx
325  * After:  baseFileName: 1./data/storage/el1/bundle/moduleName/ets/modules.abc
326  *                       2./data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
327  *         entryPoint:   bundleName/moduleName@namespace/ets/xxx
328  */
ParsePrefixBundle(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString moduleRequestName,CString recordName)329 CString ModulePathHelper::ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile,
330     [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName)
331 {
332     EcmaVM *vm = thread->GetEcmaVM();
333     moduleRequestName = moduleRequestName.substr(PREFIX_BUNDLE_LEN);
334     CString entryPoint = moduleRequestName;
335     if (jsPandaFile->IsRecordWithBundleName()) {
336         CVector<CString> vec;
337         StringHelper::SplitString(moduleRequestName, vec, 0, SEGMENTS_LIMIT_TWO);
338         if (vec.size() < SEGMENTS_LIMIT_TWO) { // LCOV_EXCL_BR_LINE
339             LOG_ECMA(FATAL) << " Exceptional module path : " << moduleRequestName << ", abc path: " <<
340                 baseFileName << ", current file name: " << recordName;
341         }
342         CString bundleName = vec[0];
343         CString moduleName = vec[1];
344         PathHelper::DeleteNamespace(moduleName);
345         baseFileName = GetBaseFileName(vm, moduleRequestName, baseFileName, bundleName, moduleName, recordName);
346     } else {
347         PathHelper::AdaptOldIsaRecord(entryPoint);
348     }
349     return entryPoint;
350 }
351 
352 
ParseNormalizedOhmUrl(JSThread * thread,CString & baseFileName,const CString & recordName,CString requestName)353 CString ModulePathHelper::ParseNormalizedOhmUrl(JSThread *thread, CString &baseFileName, const CString &recordName,
354     CString requestName)
355 {
356     ASSERT(StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED_NOT_SO));
357     CVector<CString> res = SplitNormalizedOhmurl(requestName);
358     if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
359         THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, requestName);
360     }
361     const CString& moduleName = res[NORMALIZED_MODULE_NAME_INDEX];
362     const CString& bundleName = res[NORMALIZED_BUNDLE_NAME_INDEX];
363     if (!bundleName.empty() && !moduleName.empty()) {
364         baseFileName = ConcatHspFileNameCrossBundle(bundleName, moduleName);
365     } else if (!moduleName.empty()) {
366         baseFileName = ConcatHspFileName(moduleName);
367     } else if (baseFileName.empty()) {
368         // Support multi-module card service
369         baseFileName = thread->GetEcmaVM()->GetAssetPath();
370         // test card service
371     }
372     const CString& importPath = res[NORMALIZED_IMPORT_PATH_INDEX];
373     const CString& version = res[NORMALIZED_VERSION_INDEX];
374     return ConcatUnifiedOhmUrl(bundleName, importPath, version);
375 }
376 
377 /*
378  * Before: requestName: ../xxx1/xxx2 || ./b
379  *         recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx3 || a
380  * After:  entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2 || b
381  *         baseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc || /home/user/src/a
382  */
MakeNewRecord(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)383 CString ModulePathHelper::MakeNewRecord(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName,
384     const CString &recordName, const CString &requestName)
385 {
386     CString entryPoint;
387     CString moduleRequestName = RemoveSuffix(requestName);
388     size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
389     if (pos == 0) {
390         moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./"
391     }
392     pos = recordName.rfind(PathHelper::SLASH_TAG);
393     if (pos != CString::npos) {
394         // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/../xxx1/xxx2
395         entryPoint = recordName.substr(0, pos + 1) + moduleRequestName;
396     } else {
397         entryPoint = moduleRequestName;
398     }
399     // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2
400     entryPoint = PathHelper::NormalizePath(entryPoint);
401     entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint);
402     if (!entryPoint.empty()) {
403         return entryPoint;
404     }
405     // the package name may have a '.js' suffix, try to parseThirdPartyPackage
406     entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
407     if (!entryPoint.empty()) {
408         return entryPoint;
409     }
410     // An exception is thrown when the module cannot be found in bundlePack mode.
411     if (StringHelper::StringStartWith(baseFileName, BUNDLE_INSTALL_PATH) && !jsPandaFile->IsBundlePack() &&
412         !jsPandaFile->HasRecord(entryPoint)) {
413         THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
414     }
415     // Execute abc locally
416     pos = baseFileName.rfind(PathHelper::SLASH_TAG);
417     if (pos != CString::npos) {
418         baseFileName = base::ConcatToCString(baseFileName.substr(0, pos + 1), moduleRequestName, EXT_NAME_ABC);
419     } else {
420         baseFileName = base::ConcatToCString(moduleRequestName, EXT_NAME_ABC);
421     }
422     pos = moduleRequestName.rfind(PathHelper::SLASH_TAG);
423     if (pos != CString::npos) {
424         entryPoint = moduleRequestName.substr(pos + 1);
425     } else {
426         entryPoint = moduleRequestName;
427     }
428     return entryPoint;
429 }
430 
FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)431 CString ModulePathHelper::FindOhpmEntryPoint(const JSPandaFile *jsPandaFile,
432     const CString& ohpmPath, const CString& requestName)
433 {
434     CVector<CString> vec;
435     StringHelper::SplitString(requestName, vec, 0);
436     if (vec.empty()) {
437         return {};
438     }
439     size_t maxIndex = vec.size() - 1;
440     CString ohpmKey;
441     size_t index = 0;
442     // first we find the ohpmKey by splicing the requestName
443     while (index <= maxIndex) {
444         CString maybeKey = base::ConcatToCString(ohpmPath, PathHelper::SLASH_TAG,
445                                                  StringHelper::JoinString(vec, 0, index));
446         if (jsPandaFile->FindOhmUrlInPF(maybeKey, ohpmKey)) {
447             break;
448         }
449         ++index;
450     }
451     if (ohpmKey.empty()) {
452         return {};
453     }
454     // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
455     CString entryPoint;
456     if (index == maxIndex) {
457         // requestName is a packageName
458         entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
459     } else {
460         // import a specific file or directory
461         ohpmKey = base::ConcatToCString(ohpmKey, PathHelper::SLASH_TAG,
462                                         StringHelper::JoinString(vec, index + 1, maxIndex));
463         entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
464     }
465     return entryPoint;
466 }
467 
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)468 CString ModulePathHelper::FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile,
469     const CString& requestName, const CString &recordName)
470 {
471     // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
472     CString entryPoint;
473     CString ohpmPath;
474     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
475         size_t pos = recordName.find(PathHelper::SLASH_TAG);
476         if (pos == CString::npos) {
477             LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
478             return {};
479         }
480         ohpmPath = recordName.substr(0, pos);
481         entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
482     } else {
483         // recordName: moduleName/xxx/xxx
484         CVector<CString> vec;
485         StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
486         if (vec.size() < SEGMENTS_LIMIT_TWO) {
487             LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
488             return {};
489         }
490         CString moduleName = vec[1];
491         // If namespace exists, use namespace as moduleName
492         size_t pos = moduleName.find(PathHelper::NAME_SPACE_TAG);
493         if (pos != CString::npos) {
494             moduleName = moduleName.substr(pos + 1);
495         }
496         ohpmPath = base::ConcatToCString(PACKAGE_PATH_SEGMENT, PathHelper::NAME_SPACE_TAG, moduleName);
497         entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
498         // If haven't find with namespace, then use moduleName
499         if ((pos != CString::npos) && entryPoint.empty()) {
500             moduleName = vec[1].substr(0, pos);
501             ohpmPath = base::ConcatToCString(PACKAGE_PATH_SEGMENT, PathHelper::NAME_SPACE_TAG, moduleName);
502             entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
503         }
504     }
505     if (!entryPoint.empty()) {
506         return entryPoint;
507     }
508     // find in project directory <packagePath>/<requestName>
509     return FindOhpmEntryPoint(jsPandaFile, CString(PACKAGE_PATH_SEGMENT), requestName);
510 }
511 
512 /*
513  * Before: requestName:  requestPkgName
514  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
515  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
516  */
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)517 CString ModulePathHelper::ParseOhpmPackage(const JSPandaFile *jsPandaFile,
518     const CString &recordName, const CString &requestName)
519 {
520     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
521         // this way is thirdPartyPackage import ThirdPartyPackage
522         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
523         // packageName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
524         CString packageName = info.npmPackageName;
525         size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
526         if (pos != CString::npos) {
527             packageName.erase(pos, packageName.size() - pos);
528             // ohpmPath: pkg_modules/.ohpm/pkgName/pkg_modules
529             CString ohpmPath = base::ConcatToCString(packageName, PACKAGE_PATH_SEGMENT);
530             // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
531             CString entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
532             if (!entryPoint.empty()) {
533                 return entryPoint;
534             }
535         }
536     }
537     // Import packages under the current module or project directory
538     return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
539 }
540 
541 /*
542  * Before: requestName:  requestPkgName
543  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
544  *         packagePath:  pkg_modules || node_modules
545  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
546  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)547 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
548     const CString &recordName, const CString &requestName, const CString &packagePath)
549 {
550     if (StringHelper::StringStartWith(recordName, packagePath)) {
551         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
552         CString packageName = info.npmPackageName; // pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
553         size_t pos = 0;
554         while (true) {
555             CString key = base::ConcatToCString(packageName, PathHelper::SLASH_TAG, packagePath,
556                                                 PathHelper::SLASH_TAG, requestName);
557             CString entryPoint = FindNpmEntryPoint(jsPandaFile, key);
558             if (!entryPoint.empty()) {
559                 return entryPoint;
560             }
561             size_t index = packageName.rfind(packagePath);
562             ASSERT(index > 0);
563             pos = index - 1;
564             if (pos == CString::npos || pos < 0) {
565                 break;
566             }
567             packageName.erase(pos, packageName.size() - pos);
568         }
569     }
570     return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
571 }
572 
573 /*
574  * Before: requestName:  requestPkgName
575  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
576  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
577  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)578 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
579     const CString &recordName, const CString &requestName)
580 {
581     // We need to deal with scenarios like this 'json5/' -> 'json5'
582     CString normalizeRequestName = PathHelper::NormalizePath(requestName);
583     CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
584     if (!entryPoint.empty()) {
585         return entryPoint;
586     }
587 
588     static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
589     // Package compatible with old soft link format
590     for (auto& packagePath : packagePaths) {
591         entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePath);
592         if (!entryPoint.empty()) {
593             return entryPoint;
594         }
595     }
596     return {};
597 }
598 
599 /*
600  * Before: dirPath: Undefined
601  *         fileName: Undefined
602  * After:  dirPath: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/
603  *         fileName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx.abc
604  */
ResolveCurrentPath(CString & dirPath,CString & fileName,const JSPandaFile * jsPandaFile)605 void ModulePathHelper::ResolveCurrentPath(CString &dirPath, CString &fileName, const JSPandaFile *jsPandaFile)
606 {
607     ASSERT(jsPandaFile != nullptr);
608     fileName = jsPandaFile->GetJSPandaFileDesc();
609     dirPath = PathHelper::ResolveDirPath(fileName);
610 }
611 
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)612 CString ModulePathHelper::FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
613 {
614     // if we are currently importing a specific file or directory, we will get the entryPoint here
615     CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
616     if (!entryPoint.empty()) {
617         return entryPoint;
618     }
619     // When you come here, must import a packageName
620     return jsPandaFile->GetEntryPoint(packageEntryPoint);
621 }
622 
623 /*
624  * Before: requestName:  requestPkgName
625  *         packagePath:  pkg_modules || node_modules
626  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
627  */
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)628 CString ModulePathHelper::FindPackageInTopLevel(const JSPandaFile *jsPandaFile,
629     const CString& requestName, const CString &packagePath)
630 {
631     // we find packagePath/0/xxx or packagePath/1/xxx
632     for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
633         CString levelStr(std::to_string(level));
634         CString key = base::ConcatToCString(packagePath, PathHelper::SLASH_TAG, levelStr,
635                                             PathHelper::SLASH_TAG, requestName);
636         CString entryPoint = FindNpmEntryPoint(jsPandaFile, key);
637         if (!entryPoint.empty()) {
638             return entryPoint;
639         }
640     }
641     return {};
642 }
643 
IsImportFile(const CString & moduleRequestName)644 bool ModulePathHelper::IsImportFile(const CString &moduleRequestName)
645 {
646     if (moduleRequestName[0] == PathHelper::POINT_TAG) {
647         return true;
648     }
649     size_t pos = moduleRequestName.rfind(PathHelper::POINT_TAG);
650     if (pos != CString::npos) {
651         CString suffix = moduleRequestName.substr(pos);
652         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
653             return true;
654         }
655     }
656     return false;
657 }
658 
659 /*
660  * Before: xxx/xxx.js || xxx/xxx.ts || xxx/xxx.ets ||xxx/xxx.json
661  * After:  xxx/xxx
662  */
RemoveSuffix(const CString & requestName)663 CString ModulePathHelper::RemoveSuffix(const CString &requestName)
664 {
665     CString res = requestName;
666     size_t pos = res.rfind(PathHelper::POINT_TAG);
667     if (pos != CString::npos) {
668         CString suffix = res.substr(pos);
669         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS ||
670             suffix == EXT_NAME_JSON || suffix == EXT_NAME_MJS) {
671             res.erase(pos, suffix.length());
672         }
673     }
674     return res;
675 }
676 
NeedTranstale(const CString & requestName)677 bool ModulePathHelper::NeedTranstale(const CString &requestName)
678 {
679     if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE) ||
680         StringHelper::StringStartWith(requestName, PREFIX_PACKAGE) ||
681         requestName[0] == PathHelper::POINT_TAG ||  // ./
682         (requestName[0] == PathHelper::NAME_SPACE_TAG && // @***:
683          requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
684         return false;
685     }
686     return true;
687 }
688 
689 // Adapt dynamic import using expression input, translate include NativeModule/ohpm/hsp/har.
TranstaleExpressionInput(const JSPandaFile * jsPandaFile,CString & requestPath)690 void ModulePathHelper::TranstaleExpressionInput(const JSPandaFile *jsPandaFile, CString &requestPath)
691 {
692     LOG_ECMA(DEBUG) << "Enter Translate OhmUrl for DynamicImport, requestPath: " << requestPath;
693     if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
694         requestPath = StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
695         return;
696     }
697     CString outEntryPoint;
698     // FindOhmUrlInPF: frontend generate mapping in abc,
699     // all we need to do is to find the corresponding mapping result.
700     // EXCEPTION: @ohos. @hms. is translated all by runtime.
701     if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
702         // this path for moduleName(xxx or xxx/xxx) -> moduleName/Index;
703         requestPath = outEntryPoint;
704     } else {
705         ParseCrossModuleFile(jsPandaFile, requestPath);
706     }
707     // change origin: @ohos. @hms. -> @ohos: @hms:
708     // change mapping result: @package. @bundle. @xxx. -> @package: @bundle: @xxx:
709     ChangeTag(requestPath);
710 }
711 
712 /*
713  * Before: 1. /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
714  *         2. /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
715  * After:  moduleName
716  */
GetModuleNameWithBaseFile(const CString & baseFileName)717 CString ModulePathHelper::GetModuleNameWithBaseFile(const CString &baseFileName)
718 {
719     size_t pos = CString::npos;
720     if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
721         baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
722         pos = BUNDLE_INSTALL_PATH_LEN;
723     }
724     CString moduleName;
725     if (pos != CString::npos) {
726         // baseFileName: /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
727         pos = baseFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
728         if (pos == CString::npos) { // LCOV_EXCL_BR_LINE
729             LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
730         }
731         moduleName = baseFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
732         // baseFileName /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
733         if (moduleName.find(PathHelper::POINT_STRING_TAG) != CString::npos) {
734             // length of /data/storage/el1/bundle/bundleName/
735             size_t pathLength = BUNDLE_INSTALL_PATH_LEN + moduleName.size() + 1;
736             pos = baseFileName.find(PathHelper::SLASH_TAG, pathLength);
737             moduleName = baseFileName.substr(pathLength, pos - pathLength);
738         }
739     }
740     return moduleName;
741 }
742 
743 /*
744  * Before: ets/xxx/xxx
745  * After:  bundleName/moduleName/ets/xxx/xxx
746  */
TranslateExpressionInputWithEts(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & baseFileName,const CString & requestName)747 CString ModulePathHelper::TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile,
748                                                           const CString &baseFileName, const CString &requestName)
749 {
750     EcmaVM *vm = thread->GetEcmaVM();
751     CString moduleName = GetModuleNameWithBaseFile(baseFileName);
752     CString entryPoint = base::ConcatToCString(vm->GetBundleName(), PathHelper::SLASH_TAG, moduleName,
753                                                PathHelper::SLASH_TAG, requestName);
754     if (!jsPandaFile->HasRecord(entryPoint)) {
755         return {};
756     }
757     return entryPoint;
758 }
759 
760 /*
761  * input requestPath: moduleName/src/main/xxx/xxx/xxx
762  *                    moduleName/xxx/xxx
763  * moduleName : singleLevelName or twoLevelName
764  * output requestPath: @bundle.bundleName/moduleName/xxx/xxx/xxx
765  *                     @bundle.bundleName/moduleName/xxx/xxx
766  */
ParseCrossModuleFile(const JSPandaFile * jsPandaFile,CString & requestPath)767 void ModulePathHelper::ParseCrossModuleFile(const JSPandaFile *jsPandaFile, CString &requestPath)
768 {
769     size_t pos = requestPath.find(PathHelper::SLASH_TAG);
770     if (pos == CString::npos) {
771         return;
772     }
773     CString moduleName = requestPath.substr(0, pos);
774     CString outEntryPoint;
775     // try get mapped module path by single level moduleName.
776     bool isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
777     if (!isModuleName) {
778         // retry get mapped module path by two level moduleName
779         pos = requestPath.find(PathHelper::SLASH_TAG, pos + 1);
780         if (pos == CString::npos) {
781             return;
782         }
783         moduleName = requestPath.substr(0, pos);
784         isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
785     }
786     if (isModuleName) {
787         // outEntryPoint: @bundle.bundleName/moduleName/Index
788         CString relativePath = requestPath.substr(pos);
789         // get rid of Index, get pure perfix(@bundle.bundleName/moduleName).
790         size_t index = outEntryPoint.rfind(PathHelper::SLASH_TAG);
791         // get rid of src/main. Concat perfix and input relative path.
792         if (relativePath.find(PHYCICAL_FILE_PATH.data(), 0) == 0) {
793             requestPath = base::ConcatToCString(outEntryPoint.substr(0, index), PathHelper::SLASH_TAG,
794                 requestPath.substr(pos + PHYCICAL_FILE_PATH_LEN));
795             return;
796         }
797         requestPath = outEntryPoint.substr(0, index) + requestPath.substr(pos);
798     }
799 }
800 
ParseFileNameToVMAName(const CString & filename)801 CString ModulePathHelper::ParseFileNameToVMAName(const CString &filename)
802 {
803     size_t pos = CString::npos;
804     if (filename.empty()) {
805         return VMA_NAME_ARKTS_CODE.data();
806     }
807 
808     if (filename.find(EXT_NAME_JS) != CString::npos) {
809         pos = filename.find(EXT_NAME_Z_SO);
810         if (pos == CString::npos) {
811             return VMA_NAME_ARKTS_CODE.data();
812         }
813         CString moduleName = filename.substr(0, pos);
814         pos = moduleName.rfind(PathHelper::POINT_TAG);
815         if (pos == CString::npos) {
816             return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, filename);
817         }
818         CString realModuleName = moduleName.substr(pos + 1);
819         CString realFileName = realModuleName;
820         std::transform(realFileName.begin(), realFileName.end(), realFileName.begin(), ::tolower);
821         CString file = base::ConcatToCString(PREFIX_LIB, realFileName, EXT_NAME_Z_SO, PathHelper::SLASH_TAG,
822                                              realModuleName, EXT_NAME_JS);
823         return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, file);
824     }
825 
826     if (filename.find(EXT_NAME_ABC) != CString::npos) {
827         pos = filename.find(BUNDLE_INSTALL_PATH);
828         if (pos == CString::npos) {
829             return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, filename);
830         }
831         CString file = filename.substr(BUNDLE_INSTALL_PATH_LEN);
832         return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, file);
833     }
834 
835     return VMA_NAME_ARKTS_CODE.data();
836 }
837 
GetPkgContextInfoListElements(EcmaVM * vm,const CString & moduleName,const CString & packageName)838 CVector<CString> ModulePathHelper::GetPkgContextInfoListElements(EcmaVM *vm, const CString &moduleName,
839                                                                  const CString &packageName)
840 {
841     CVector<CString> resultList;
842     if (packageName.empty()) {
843         return resultList;
844     }
845     CMap<CString, CMap<CString, CVector<CString>>> pkgContextList = vm->GetPkgContextInfoList();
846     if (pkgContextList.find(moduleName) == pkgContextList.end()) {
847         return resultList;
848     }
849     CMap<CString, CVector<CString>> pkgList = pkgContextList[moduleName];
850     if (pkgList.find(packageName) == pkgList.end()) {
851         return resultList;
852     }
853     resultList = pkgList[packageName];
854     return resultList;
855 }
856 
ConcatImportFileNormalizedOhmurl(const CString & recordPath,const CString & requestName,const CString & version)857 CString ModulePathHelper::ConcatImportFileNormalizedOhmurl(const CString &recordPath, const CString &requestName,
858     const CString &version)
859 {
860     return base::ConcatToCString(recordPath, requestName, PathHelper::NORMALIZED_OHMURL_TAG, version);
861 }
862 
ConcatNativeSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & version)863 CString ModulePathHelper::ConcatNativeSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
864     const CString &pkgName, const CString &version)
865 {
866     return base::ConcatToCString(PREFIX_NORMALIZED_SO, PathHelper::NORMALIZED_OHMURL_TAG, moduleName,
867         PathHelper::NORMALIZED_OHMURL_TAG, bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgName,
868         PathHelper::NORMALIZED_OHMURL_TAG, version);
869 }
870 
ConcatNotSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & entryPath,const CString & version)871 CString ModulePathHelper::ConcatNotSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
872     const CString &pkgName, const CString &entryPath, const CString &version)
873 {
874     return base::ConcatToCString(PREFIX_NORMALIZED_NOT_SO, PathHelper::NORMALIZED_OHMURL_TAG, moduleName,
875         PathHelper::NORMALIZED_OHMURL_TAG, bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgName,
876         PathHelper::SLASH_TAG, entryPath, PathHelper::NORMALIZED_OHMURL_TAG, version);
877 }
878 
NeedTranslateToNormalized(const CString & requestName)879 bool ModulePathHelper::NeedTranslateToNormalized(const CString &requestName)
880 {
881     // if start with @normalized:xxx @native:xxx.xxx @ohos:xxx
882     // no translation is required
883     if (StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED) ||
884         (requestName[0] == PathHelper::NAME_SPACE_TAG &&
885          requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
886             return false;
887     }
888     return true;
889 }
890 
TranslateExpressionToNormalized(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,CString & requestPath)891 CString ModulePathHelper::TranslateExpressionToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
892     [[maybe_unused]] CString &baseFileName, const CString &recordName, CString &requestPath)
893 {
894     if (!NeedTranslateToNormalized(requestPath)) {
895         return requestPath;
896     }
897     if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
898         return StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
899     }
900     EcmaVM *vm = thread->GetEcmaVM();
901     CString inputPath = requestPath;
902     if (IsImportFile(requestPath)) {
903         CString entryPoint = ConcatImportFileNormalizedOhmurlWithRecordName(thread, jsPandaFile, baseFileName,
904             recordName, requestPath);
905         if (entryPoint.empty()) {
906             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
907         }
908     } else if (StringHelper::StringStartWith(requestPath, PREFIX_ETS)) {
909         size_t pos = recordName.find(PREFIX_ETS);
910         if (pos != CString::npos) {
911             requestPath = ConcatImportFileNormalizedOhmurl(recordName.substr(0, pos), requestPath);
912         }
913         if (!jsPandaFile->HasRecord(requestPath)) {
914             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
915         }
916     } else {
917         ConcatOtherNormalizedOhmurl(vm, jsPandaFile, baseFileName, requestPath);
918     }
919     return requestPath;
920 }
921 
922 /*
923  * Before: requestPath: 1. @ohos.xxx
924  *                      2. har or har/xxx/xxx
925  *                      3. hsp or hsp/xxx/xxx
926  *                      4. libentry.so
927  * After:  requestPath: 1. @ohos:xxx or @native:xxx.xxx
928  *                      2. @normalized:N&moduleName&bundleName&entryPath&version
929  *                      3. @normalized:N&moduleName&bundleName&entryPath&
930  *                      4. @normalized:Y&&bundleName&entryPath&version
931  */
ConcatOtherNormalizedOhmurl(EcmaVM * vm,const JSPandaFile * jsPandaFile,const CString & baseFileName,CString & requestPath)932 void ModulePathHelper::ConcatOtherNormalizedOhmurl(EcmaVM *vm, const JSPandaFile *jsPandaFile,
933     [[maybe_unused]] const CString &baseFileName, CString &requestPath)
934 {
935     CString currentModuleName = GetModuleNameWithBaseFile(baseFileName);
936     if (currentModuleName.empty()) {
937         //baseFileName: X:\xxx\entry\.preview\default\intermediates\assets\default\ets\modules.abc
938         currentModuleName = vm->GetModuleName();
939     }
940     CString pkgName = vm->GetPkgNameWithAlias(requestPath);
941     CVector<CString> data = GetPkgContextInfoListElements(vm, currentModuleName, pkgName);
942     if (!data.empty()) {
943         CString entryPath;
944         requestPath = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
945         return;
946     }
947     // When requestName contains '/', it is considered to be a file path.
948     CString result;
949     size_t filePathPos = requestPath.find(PathHelper::SLASH_TAG);
950     if (filePathPos != CString::npos) {
951         result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
952         // Try to get the PkgContextInfo by two levels alias
953         if (result.empty()) {
954             filePathPos = requestPath.find(PathHelper::SLASH_TAG, filePathPos + 1);
955             if (filePathPos != CString::npos) {
956                 result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
957             }
958         }
959     }
960     if (result.empty()) {
961         CString outEntryPoint;
962         if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
963             requestPath = outEntryPoint;
964         }
965         ChangeTag(requestPath);
966         return;
967     }
968     requestPath = result;
969 }
970 
ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM * vm,size_t filePathPos,const CString & moduleName,const CString & requestPath)971 CString ModulePathHelper::ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM *vm, size_t filePathPos,
972     const CString &moduleName, const CString &requestPath)
973 {
974     CString result;
975     CString alias = requestPath.substr(0, filePathPos);
976     CString entryPath = requestPath.substr(filePathPos + 1);
977     CString pkgName = vm->GetPkgNameWithAlias(alias);
978     CVector<CString> data = GetPkgContextInfoListElements(vm, moduleName, pkgName);
979     if (!data.empty()) {
980         result = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
981     }
982     return result;
983 }
984 
ConcatNormalizedOhmurlWithData(const CVector<CString> & data,const CString & pkgName,CString & entryPath)985 CString ModulePathHelper::ConcatNormalizedOhmurlWithData(const CVector<CString> &data, const CString &pkgName,
986     CString &entryPath)
987 {
988     const CString &bundleName = data[PKGINFO_BUDNLE_NAME_INDEX];
989     const CString &moduleName = data[PKGINFO_MODULE_NAME_INDEX];
990     const CString &version = data[PKGINFO_VERSION_INDEX];
991     if (entryPath.empty()) {
992         entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
993     }
994     const CString &isSO = data[PKGINFO_IS_SO_INDEX];
995     if (entryPath.find(PathHelper::CURRENT_DIREATORY_TAG) == 0) {
996         entryPath = entryPath.substr(CURRENT_DIREATORY_TAG_LEN);
997     }
998     if (isSO == TRUE_FLAG) {
999         return ConcatNativeSoNormalizedOhmurl(moduleName, bundleName, pkgName, version);
1000     } else {
1001         entryPath = RemoveSuffix(entryPath);
1002         return ConcatNotSoNormalizedOhmurl(moduleName, bundleName, pkgName, entryPath, version);
1003     }
1004 }
1005 
TranslateNapiFileRequestPath(JSThread * thread,const CString & modulePath,const CString & requestName)1006 CString ModulePathHelper::TranslateNapiFileRequestPath(JSThread *thread, const CString &modulePath,
1007     const CString &requestName)
1008 {
1009     if (thread->GetEcmaVM()->IsNormalizedOhmUrlPack()) {
1010         CString moduleName = GetModuleNameWithPath(modulePath);
1011         CString res(1, PathHelper::NORMALIZED_OHMURL_TAG);
1012         base::AppendToBaseString(res, moduleName, PHYCICAL_FILE_PATH.data(),
1013             PathHelper::SLASH_TAG, requestName, PathHelper::NORMALIZED_OHMURL_TAG);
1014         return res;
1015     } else {
1016         return base::ConcatToCString(modulePath, PathHelper::SLASH_TAG, requestName);
1017     }
1018 }
1019 
SplitNormalizedOhmurl(const CString & ohmurl)1020 CVector<CString> ModulePathHelper::SplitNormalizedOhmurl(const CString &ohmurl)
1021 {
1022     CVector<CString> res;
1023     size_t start = 0;
1024     size_t pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG);
1025     while (pos != CString::npos) {
1026         CString element = ohmurl.substr(start, pos - start);
1027         res.emplace_back(element);
1028         start = pos + 1;
1029         pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG, start);
1030     }
1031     CString tail = ohmurl.substr(start);
1032     res.emplace_back(tail);
1033     return res;
1034 }
1035 
SplitNormalizedRecordName(const CString & recordName)1036 CVector<CString> ModulePathHelper::SplitNormalizedRecordName(const CString &recordName)
1037 {
1038     CVector<CString> res(NORMALIZED_OHMURL_ARGS_NUM);
1039     int index = NORMALIZED_OHMURL_ARGS_NUM - 1;
1040     CString temp;
1041     int endIndex = static_cast<int>(recordName.size()) - 1;
1042     for (int i = endIndex; i >= 0; i--) {
1043         char element = recordName[i];
1044         if (element == PathHelper::NORMALIZED_OHMURL_TAG) {
1045             res[index] = temp;
1046             index--;
1047             temp = "";
1048             continue;
1049         }
1050         temp = element + temp;
1051     }
1052     if (!temp.empty()) {
1053         res[index] = temp;
1054     }
1055     return res;
1056 }
1057 
1058 /*
1059  * Before: 1. bundleName/moduleName/xxx/xxx
1060            2. bunldeName&moduleName/xxx/xxx&
1061  * After:  bundleName
1062  */
GetBundleNameWithRecordName(EcmaVM * vm,const CString & recordName)1063 CString ModulePathHelper::GetBundleNameWithRecordName(EcmaVM *vm, const CString &recordName)
1064 {
1065     CString bundleName;
1066     if (vm->IsNormalizedOhmUrlPack()) {
1067         CVector<CString> res = ModulePathHelper::SplitNormalizedRecordName(recordName);
1068         bundleName = res[ModulePathHelper::NORMALIZED_BUNDLE_NAME_INDEX];
1069         if (bundleName.empty()) {
1070             bundleName = vm->GetBundleName();
1071         }
1072     } else {
1073         size_t pos = recordName.find(PathHelper::SLASH_TAG);
1074         bundleName = recordName.substr(0, pos);
1075     }
1076     return bundleName;
1077 }
1078 
1079 // this function convert for ESModule name string(Utf8)
Utf8ConvertToString(JSThread * thread,JSTaggedValue str)1080 CString ModulePathHelper::Utf8ConvertToString(JSThread *thread, JSTaggedValue str)
1081 {
1082     return EcmaStringAccessor(str).Utf8ConvertToString(thread);
1083 }
1084 
1085 // check if input is ohmurl's ets/ts/js
IsOhmUrl(const CString & str)1086 bool ModulePathHelper::IsOhmUrl(const CString &str)
1087 {
1088     if (StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_BUNDLE) ||
1089         StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_PACKAGE) ||
1090         StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_NORMALIZED_NOT_SO)) {
1091         return true;
1092     }
1093     return false;
1094 }
1095 
CheckAndGetRecordName(JSThread * thread,const CString & ohmUrl,CString & recordName)1096 bool ModulePathHelper::CheckAndGetRecordName(JSThread *thread, const CString &ohmUrl, CString &recordName)
1097 {
1098     if (StringHelper::StringStartWith(ohmUrl, PREFIX_BUNDLE)) {
1099         recordName = ohmUrl.substr(PREFIX_BUNDLE_LEN);
1100         return true;
1101     } else if (StringHelper::StringStartWith(ohmUrl, PREFIX_PACKAGE)) {
1102         recordName = ohmUrl.substr(PREFIX_PACKAGE_LEN);
1103         return true;
1104     } else if (StringHelper::StringStartWith(ohmUrl, PREFIX_NORMALIZED_NOT_SO)) {
1105         CString str;
1106         recordName = ModulePathHelper::ParseNormalizedOhmUrl(thread, str, " ", ohmUrl);
1107         return true;
1108     }
1109     LOG_ECMA(ERROR) << "the requested OhmUrl: '" + ohmUrl +
1110         ", doesn't match current OhmUrl rule, please check build result.";
1111     return false;
1112 }
1113 
1114 /*
1115  * Before: ABC: /data/storage/el1/bundle/xxx/xxx/xxx.abc
1116  * Before: ETS_MODULES: /data/storage/el1/bundle/xxx/ets/modules.abc
1117  */
ValidateAbcPath(const CString & baseFileName,ValidateFilePath checkMode)1118 bool ModulePathHelper::ValidateAbcPath(const CString &baseFileName, ValidateFilePath checkMode)
1119 {
1120     if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
1121         baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
1122         if (checkMode == ValidateFilePath::ETS_MODULES &&
1123             baseFileName.rfind(MERGE_ABC_ETS_MODULES) != CString::npos) {
1124             return true;
1125         }
1126         if (checkMode == ValidateFilePath::ABC &&
1127             baseFileName.rfind(ABC) != CString::npos) {
1128             return true;
1129         }
1130     }
1131     return false;
1132 }
1133 
ResolveOhmUrl(std::string ohmUrl)1134 std::pair<std::string, std::string> ModulePathHelper::ResolveOhmUrl(std::string ohmUrl)
1135 {
1136     CString url(ohmUrl);
1137     if (StringHelper::StringStartWith(url, PREFIX_BUNDLE)) {
1138         return ResolveOhmUrlStartWithBundle(ohmUrl);
1139     }
1140     if (StringHelper::StringStartWith(url, PREFIX_NORMALIZED_NOT_SO)) {
1141         return ResolveOhmUrlStartWithNormalized(ohmUrl);
1142     }
1143     LOG_FULL(FATAL) << "Invalid Ohm url, please check. OhmUrl: " << ohmUrl;
1144     return {"", ""};
1145 }
1146 
ResolveOhmUrlStartWithBundle(const std::string & ohmUrl)1147 std::pair<std::string, std::string> ModulePathHelper::ResolveOhmUrlStartWithBundle(const std::string &ohmUrl)
1148 {
1149     std::string moduleRequestName(ohmUrl.substr(PREFIX_BUNDLE_LEN));
1150     size_t index = moduleRequestName.find('/');
1151     index = moduleRequestName.find('/', index + 1);
1152     if (index == std::string::npos) {
1153         LOG_FULL(FATAL) << "Invalid Ohm url, please check. OhmUrl: " << ohmUrl;
1154     }
1155     std::string bundleAndModuleName = moduleRequestName.substr(0, index);
1156     std::string filePath = moduleRequestName.substr(index + 1);
1157     return {filePath, bundleAndModuleName};
1158 }
1159 
ResolveOhmUrlStartWithNormalized(const std::string & ohmUrl)1160 std::pair<std::string, std::string> ModulePathHelper::ResolveOhmUrlStartWithNormalized(const std::string &ohmUrl)
1161 {
1162     CVector<CString> res = SplitNormalizedOhmurl(CString(ohmUrl));
1163     if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
1164         LOG_FULL(FATAL) << "Invalid Ohm url, please check. OhmUrl: " << ohmUrl;
1165     }
1166     std::string moduleName(res[NORMALIZED_MODULE_NAME_INDEX]);
1167     std::string bundleName(res[NORMALIZED_BUNDLE_NAME_INDEX]);
1168     std::string path(res[NORMALIZED_IMPORT_PATH_INDEX]);
1169     if (bundleName.empty() || moduleName.empty() || path.empty()) {
1170         LOG_FULL(FATAL) << "Invalid Ohm url, please check. OhmUrl: " << ohmUrl;
1171     }
1172     return {path, bundleName + PathHelper::SLASH_TAG + moduleName};
1173 }
1174 }  // namespace panda::ecmascript