• 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, path,
210         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     CString version;
274     CString entryPath;
275     if (!data.empty()) {
276         version = data[PKGINFO_VERSION_INDEX];
277         entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
278     } else {
279         return oldEntryPoint;
280     }
281     // If the subPath starts with '.test', it is a preview test, no need to splice the entry path.
282     CString subPath = oldEntryPoint.substr(pathPos + 1);
283     if (StringHelper::StringStartWith(subPath, PREVIER_TEST_DIR)) {
284         return ConcatPreviewTestUnifiedOhmUrl("", pkgname, path, version);
285     }
286     // When the entry path ends with a slash (/), use the entry path to concatenate ohmurl.
287     if (!entryPath.empty() && StringHelper::StringEndWith(entryPath, PathHelper::SLASH_TAG)) {
288         size_t endPos = entryPath.rfind(PathHelper::SLASH_TAG);
289         entryPath = entryPath.substr(0, endPos);
290         return ConcatUnifiedOhmUrl("", pkgname, entryPath, path, version);
291     }
292     // bundleName and entryPath is empty.
293     return ConcatUnifiedOhmUrl("", pkgname, "", path, version);
294 }
295 
296 /*
297  * Before: recordName: bundleName/moduleName@namespace/xxx/xxx.abc
298  * After: Intra-application cross hap:   /data/storage/el1/bundle/bundleName/ets/modules.abc
299  *        Cross-application:             /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
300  */
ParseUrl(EcmaVM * vm,const CString & recordName)301 CString ModulePathHelper::ParseUrl(EcmaVM *vm, const CString &recordName)
302 {
303     CVector<CString> vec;
304     StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
305     if (vec.size() < SEGMENTS_LIMIT_TWO) {
306         LOG_ECMA(DEBUG) << "ParseUrl SplitString filed, please check Url" << recordName;
307         return {};
308     }
309     CString bundleName = vec[0];
310     CString moduleName = vec[1];
311     PathHelper::DeleteNamespace(moduleName);
312 
313     CString baseFileName;
314     if (bundleName != vm->GetBundleName()) {
315         // Cross-application
316         baseFileName = base::ConcatToCString(BUNDLE_INSTALL_PATH, bundleName, PathHelper::SLASH_TAG, moduleName,
317             PathHelper::SLASH_TAG, moduleName, MERGE_ABC_ETS_MODULES);
318     } else {
319         // Intra-application cross hap
320         baseFileName = base::ConcatToCString(BUNDLE_INSTALL_PATH, moduleName, MERGE_ABC_ETS_MODULES);
321     }
322     return baseFileName;
323 }
324 
325 /*
326  * Before: moduleRequestName: @bundle:bundleName/moduleName@namespace/ets/xxx
327  * After:  baseFileName: 1./data/storage/el1/bundle/moduleName/ets/modules.abc
328  *                       2./data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
329  *         entryPoint:   bundleName/moduleName@namespace/ets/xxx
330  */
ParsePrefixBundle(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString moduleRequestName,CString recordName)331 CString ModulePathHelper::ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile,
332     [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName)
333 {
334     EcmaVM *vm = thread->GetEcmaVM();
335     moduleRequestName = moduleRequestName.substr(PREFIX_BUNDLE_LEN);
336     CString entryPoint = moduleRequestName;
337     if (jsPandaFile->IsRecordWithBundleName()) {
338         CVector<CString> vec;
339         StringHelper::SplitString(moduleRequestName, vec, 0, SEGMENTS_LIMIT_TWO);
340         if (vec.size() < SEGMENTS_LIMIT_TWO) { // LCOV_EXCL_BR_LINE
341             LOG_ECMA(FATAL) << " Exceptional module path : " << moduleRequestName << ", abc path: " <<
342                 baseFileName << ", current file name: " << recordName;
343         }
344         CString bundleName = vec[0];
345         CString moduleName = vec[1];
346         PathHelper::DeleteNamespace(moduleName);
347         baseFileName = GetBaseFileName(vm, moduleRequestName, baseFileName, bundleName, moduleName, recordName);
348     } else {
349         PathHelper::AdaptOldIsaRecord(entryPoint);
350     }
351     return entryPoint;
352 }
353 
354 
ParseNormalizedOhmUrl(JSThread * thread,CString & baseFileName,const CString & recordName,CString requestName)355 CString ModulePathHelper::ParseNormalizedOhmUrl(JSThread *thread, CString &baseFileName, const CString &recordName,
356     CString requestName)
357 {
358     ASSERT(StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED_NOT_SO));
359     CVector<CString> res = SplitNormalizedOhmurl(requestName);
360     if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
361         THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, requestName);
362     }
363     const CString& moduleName = res[NORMALIZED_MODULE_NAME_INDEX];
364     const CString& bundleName = res[NORMALIZED_BUNDLE_NAME_INDEX];
365     if (!bundleName.empty() && !moduleName.empty()) {
366         baseFileName = ConcatHspFileNameCrossBundle(bundleName, moduleName);
367     } else if (!moduleName.empty()) {
368         baseFileName = ConcatHspFileName(moduleName);
369     } else if (baseFileName.empty()) {
370         // Support multi-module card service
371         baseFileName = thread->GetEcmaVM()->GetAssetPath();
372         // test card service
373     }
374     const CString& importPath = res[NORMALIZED_IMPORT_PATH_INDEX];
375     const CString& version = res[NORMALIZED_VERSION_INDEX];
376     return ConcatUnifiedOhmUrl(bundleName, importPath, version);
377 }
378 
379 /*
380  * Before: requestName: ../xxx1/xxx2 || ./b
381  *         recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx3 || a
382  * After:  entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2 || b
383  *         baseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc || /home/user/src/a
384  */
MakeNewRecord(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)385 CString ModulePathHelper::MakeNewRecord(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName,
386     const CString &recordName, const CString &requestName)
387 {
388     CString entryPoint;
389     CString moduleRequestName = RemoveSuffix(requestName);
390     size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
391     if (pos == 0) {
392         moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./"
393     }
394     pos = recordName.rfind(PathHelper::SLASH_TAG);
395     if (pos != CString::npos) {
396         // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/../xxx1/xxx2
397         entryPoint = recordName.substr(0, pos + 1) + moduleRequestName;
398     } else {
399         entryPoint = moduleRequestName;
400     }
401     // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2
402     entryPoint = PathHelper::NormalizePath(entryPoint);
403     entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint);
404     if (!entryPoint.empty()) {
405         return entryPoint;
406     }
407     // the package name may have a '.js' suffix, try to parseThirdPartyPackage
408     entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
409     if (!entryPoint.empty()) {
410         return entryPoint;
411     }
412     // An exception is thrown when the module cannot be found in bundlePack mode.
413     if (StringHelper::StringStartWith(baseFileName, BUNDLE_INSTALL_PATH) && !jsPandaFile->IsBundlePack() &&
414         !jsPandaFile->HasRecord(entryPoint)) {
415         THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
416     }
417     // Execute abc locally
418     pos = baseFileName.rfind(PathHelper::SLASH_TAG);
419     if (pos != CString::npos) {
420         baseFileName = base::ConcatToCString(baseFileName.substr(0, pos + 1), moduleRequestName, EXT_NAME_ABC);
421     } else {
422         baseFileName = base::ConcatToCString(moduleRequestName, EXT_NAME_ABC);
423     }
424     pos = moduleRequestName.rfind(PathHelper::SLASH_TAG);
425     if (pos != CString::npos) {
426         entryPoint = moduleRequestName.substr(pos + 1);
427     } else {
428         entryPoint = moduleRequestName;
429     }
430     return entryPoint;
431 }
432 
FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)433 CString ModulePathHelper::FindOhpmEntryPoint(const JSPandaFile *jsPandaFile,
434     const CString& ohpmPath, const CString& requestName)
435 {
436     CVector<CString> vec;
437     StringHelper::SplitString(requestName, vec, 0);
438     if (vec.empty()) {
439         return {};
440     }
441     size_t maxIndex = vec.size() - 1;
442     CString ohpmKey;
443     size_t index = 0;
444     // first we find the ohpmKey by splicing the requestName
445     while (index <= maxIndex) {
446         CString maybeKey = base::ConcatToCString(ohpmPath, PathHelper::SLASH_TAG,
447                                                  StringHelper::JoinString(vec, 0, index));
448         if (jsPandaFile->FindOhmUrlInPF(maybeKey, ohpmKey)) {
449             break;
450         }
451         ++index;
452     }
453     if (ohpmKey.empty()) {
454         return {};
455     }
456     // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
457     CString entryPoint;
458     if (index == maxIndex) {
459         // requestName is a packageName
460         entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
461     } else {
462         // import a specific file or directory
463         ohpmKey = base::ConcatToCString(ohpmKey, PathHelper::SLASH_TAG,
464                                         StringHelper::JoinString(vec, index + 1, maxIndex));
465         entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
466     }
467     return entryPoint;
468 }
469 
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)470 CString ModulePathHelper::FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile,
471     const CString& requestName, const CString &recordName)
472 {
473     // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
474     CString entryPoint;
475     CString ohpmPath;
476     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
477         size_t pos = recordName.find(PathHelper::SLASH_TAG);
478         if (pos == CString::npos) {
479             LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
480             return {};
481         }
482         ohpmPath = recordName.substr(0, pos);
483         entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
484     } else {
485         // recordName: moduleName/xxx/xxx
486         CVector<CString> vec;
487         StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
488         if (vec.size() < SEGMENTS_LIMIT_TWO) {
489             LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
490             return {};
491         }
492         CString moduleName = vec[1];
493         // If namespace exists, use namespace as moduleName
494         size_t pos = moduleName.find(PathHelper::NAME_SPACE_TAG);
495         if (pos != CString::npos) {
496             moduleName = moduleName.substr(pos + 1);
497         }
498         ohpmPath = base::ConcatToCString(PACKAGE_PATH_SEGMENT, PathHelper::NAME_SPACE_TAG, moduleName);
499         entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
500         // If haven't find with namespace, then use moduleName
501         if ((pos != CString::npos) && entryPoint.empty()) {
502             moduleName = vec[1].substr(0, pos);
503             ohpmPath = base::ConcatToCString(PACKAGE_PATH_SEGMENT, PathHelper::NAME_SPACE_TAG, moduleName);
504             entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
505         }
506     }
507     if (!entryPoint.empty()) {
508         return entryPoint;
509     }
510     // find in project directory <packagePath>/<requestName>
511     return FindOhpmEntryPoint(jsPandaFile, CString(PACKAGE_PATH_SEGMENT), requestName);
512 }
513 
514 /*
515  * Before: requestName:  requestPkgName
516  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
517  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
518  */
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)519 CString ModulePathHelper::ParseOhpmPackage(const JSPandaFile *jsPandaFile,
520     const CString &recordName, const CString &requestName)
521 {
522     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
523         // this way is thirdPartyPackage import ThirdPartyPackage
524         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
525         // packageName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
526         CString packageName = info.npmPackageName;
527         size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
528         if (pos != CString::npos) {
529             packageName.erase(pos, packageName.size() - pos);
530             // ohpmPath: pkg_modules/.ohpm/pkgName/pkg_modules
531             CString ohpmPath = base::ConcatToCString(packageName, PACKAGE_PATH_SEGMENT);
532             // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
533             CString entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
534             if (!entryPoint.empty()) {
535                 return entryPoint;
536             }
537         }
538     }
539     // Import packages under the current module or project directory
540     return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
541 }
542 
543 /*
544  * Before: requestName:  requestPkgName
545  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
546  *         packagePath:  pkg_modules || node_modules
547  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
548  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)549 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
550     const CString &recordName, const CString &requestName, const CString &packagePath)
551 {
552     if (StringHelper::StringStartWith(recordName, packagePath)) {
553         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
554         CString packageName = info.npmPackageName; // pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
555         size_t pos = 0;
556         while (true) {
557             CString key = base::ConcatToCString(packageName, PathHelper::SLASH_TAG, packagePath,
558                                                 PathHelper::SLASH_TAG, requestName);
559             CString entryPoint = FindNpmEntryPoint(jsPandaFile, key);
560             if (!entryPoint.empty()) {
561                 return entryPoint;
562             }
563             size_t index = packageName.rfind(packagePath);
564             ASSERT(index > 0);
565             pos = index - 1;
566             if (pos == CString::npos || pos < 0) {
567                 break;
568             }
569             packageName.erase(pos, packageName.size() - pos);
570         }
571     }
572     return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
573 }
574 
575 /*
576  * Before: requestName:  requestPkgName
577  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
578  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
579  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)580 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
581     const CString &recordName, const CString &requestName)
582 {
583     // We need to deal with scenarios like this 'json5/' -> 'json5'
584     CString normalizeRequestName = PathHelper::NormalizePath(requestName);
585     CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
586     if (!entryPoint.empty()) {
587         return entryPoint;
588     }
589 
590     static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
591     // Package compatible with old soft link format
592     for (auto& packagePath : packagePaths) {
593         entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePath);
594         if (!entryPoint.empty()) {
595             return entryPoint;
596         }
597     }
598     return {};
599 }
600 
601 /*
602  * Before: dirPath: Undefined
603  *         fileName: Undefined
604  * After:  dirPath: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/
605  *         fileName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx.abc
606  */
ResolveCurrentPath(CString & dirPath,CString & fileName,const JSPandaFile * jsPandaFile)607 void ModulePathHelper::ResolveCurrentPath(CString &dirPath, CString &fileName, const JSPandaFile *jsPandaFile)
608 {
609     ASSERT(jsPandaFile != nullptr);
610     fileName = jsPandaFile->GetJSPandaFileDesc();
611     dirPath = PathHelper::ResolveDirPath(fileName);
612 }
613 
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)614 CString ModulePathHelper::FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
615 {
616     // if we are currently importing a specific file or directory, we will get the entryPoint here
617     CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
618     if (!entryPoint.empty()) {
619         return entryPoint;
620     }
621     // When you come here, must import a packageName
622     return jsPandaFile->GetEntryPoint(packageEntryPoint);
623 }
624 
625 /*
626  * Before: requestName:  requestPkgName
627  *         packagePath:  pkg_modules || node_modules
628  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
629  */
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)630 CString ModulePathHelper::FindPackageInTopLevel(const JSPandaFile *jsPandaFile,
631     const CString& requestName, const CString &packagePath)
632 {
633     // we find packagePath/0/xxx or packagePath/1/xxx
634     for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
635         CString levelStr(std::to_string(level));
636         CString key = base::ConcatToCString(packagePath, PathHelper::SLASH_TAG, levelStr,
637                                             PathHelper::SLASH_TAG, requestName);
638         CString entryPoint = FindNpmEntryPoint(jsPandaFile, key);
639         if (!entryPoint.empty()) {
640             return entryPoint;
641         }
642     }
643     return {};
644 }
645 
IsImportFile(const CString & moduleRequestName)646 bool ModulePathHelper::IsImportFile(const CString &moduleRequestName)
647 {
648     if (moduleRequestName[0] == PathHelper::POINT_TAG) {
649         return true;
650     }
651     size_t pos = moduleRequestName.rfind(PathHelper::POINT_TAG);
652     if (pos != CString::npos) {
653         CString suffix = moduleRequestName.substr(pos);
654         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
655             return true;
656         }
657     }
658     return false;
659 }
660 
661 /*
662  * Before: xxx/xxx.js || xxx/xxx.ts || xxx/xxx.ets ||xxx/xxx.json
663  * After:  xxx/xxx
664  */
RemoveSuffix(const CString & requestName)665 CString ModulePathHelper::RemoveSuffix(const CString &requestName)
666 {
667     CString res = requestName;
668     size_t pos = res.rfind(PathHelper::POINT_TAG);
669     if (pos != CString::npos) {
670         CString suffix = res.substr(pos);
671         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS ||
672             suffix == EXT_NAME_JSON || suffix == EXT_NAME_MJS) {
673             res.erase(pos, suffix.length());
674         }
675     }
676     return res;
677 }
678 
NeedTranstale(const CString & requestName)679 bool ModulePathHelper::NeedTranstale(const CString &requestName)
680 {
681     if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE) ||
682         StringHelper::StringStartWith(requestName, PREFIX_PACKAGE) ||
683         requestName[0] == PathHelper::POINT_TAG ||  // ./
684         (requestName[0] == PathHelper::NAME_SPACE_TAG && // @***:
685          requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
686         return false;
687     }
688     return true;
689 }
690 
691 // Adapt dynamic import using expression input, translate include NativeModule/ohpm/hsp/har.
TranstaleExpressionInput(const JSPandaFile * jsPandaFile,CString & requestPath)692 void ModulePathHelper::TranstaleExpressionInput(const JSPandaFile *jsPandaFile, CString &requestPath)
693 {
694     LOG_ECMA(DEBUG) << "Enter Translate OhmUrl for DynamicImport, requestPath: " << requestPath;
695     if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
696         requestPath = StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
697         return;
698     }
699     CString outEntryPoint;
700     // FindOhmUrlInPF: frontend generate mapping in abc,
701     // all we need to do is to find the corresponding mapping result.
702     // EXCEPTION: @ohos. @hms. is translated all by runtime.
703     if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
704         // this path for moduleName(xxx or xxx/xxx) -> moduleName/Index;
705         requestPath = outEntryPoint;
706     } else {
707         ParseCrossModuleFile(jsPandaFile, requestPath);
708     }
709     // change origin: @ohos. @hms. -> @ohos: @hms:
710     // change mapping result: @package. @bundle. @xxx. -> @package: @bundle: @xxx:
711     ChangeTag(requestPath);
712 }
713 
714 /*
715  * Before: 1. /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
716  *         2. /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
717  * After:  moduleName
718  */
GetModuleNameWithBaseFile(const CString & baseFileName)719 CString ModulePathHelper::GetModuleNameWithBaseFile(const CString &baseFileName)
720 {
721     size_t pos = CString::npos;
722     if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
723         baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
724         pos = BUNDLE_INSTALL_PATH_LEN;
725     }
726     CString moduleName;
727     if (pos != CString::npos) {
728         // baseFileName: /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
729         pos = baseFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
730         if (pos == CString::npos) { // LCOV_EXCL_BR_LINE
731             LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
732         }
733         moduleName = baseFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
734         // baseFileName /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
735         if (moduleName.find(PathHelper::POINT_STRING_TAG) != CString::npos) {
736             // length of /data/storage/el1/bundle/bundleName/
737             size_t pathLength = BUNDLE_INSTALL_PATH_LEN + moduleName.size() + 1;
738             pos = baseFileName.find(PathHelper::SLASH_TAG, pathLength);
739             moduleName = baseFileName.substr(pathLength, pos - pathLength);
740         }
741     }
742     return moduleName;
743 }
744 
745 /*
746  * Before: ets/xxx/xxx
747  * After:  bundleName/moduleName/ets/xxx/xxx
748  */
TranslateExpressionInputWithEts(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & baseFileName,const CString & requestName)749 CString ModulePathHelper::TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile,
750                                                           const CString &baseFileName, const CString &requestName)
751 {
752     EcmaVM *vm = thread->GetEcmaVM();
753     CString moduleName = GetModuleNameWithBaseFile(baseFileName);
754     CString entryPoint = base::ConcatToCString(vm->GetBundleName(), PathHelper::SLASH_TAG, moduleName,
755                                                PathHelper::SLASH_TAG, requestName);
756     if (!jsPandaFile->HasRecord(entryPoint)) {
757         return {};
758     }
759     return entryPoint;
760 }
761 
762 /*
763  * input requestPath: moduleName/src/main/xxx/xxx/xxx
764  *                    moduleName/xxx/xxx
765  * moduleName : singleLevelName or twoLevelName
766  * output requestPath: @bundle.bundleName/moduleName/xxx/xxx/xxx
767  *                     @bundle.bundleName/moduleName/xxx/xxx
768  */
ParseCrossModuleFile(const JSPandaFile * jsPandaFile,CString & requestPath)769 void ModulePathHelper::ParseCrossModuleFile(const JSPandaFile *jsPandaFile, CString &requestPath)
770 {
771     size_t pos = requestPath.find(PathHelper::SLASH_TAG);
772     if (pos == CString::npos) {
773         return;
774     }
775     CString moduleName = requestPath.substr(0, pos);
776     CString outEntryPoint;
777     // try get mapped module path by single level moduleName.
778     bool isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
779     if (!isModuleName) {
780         // retry get mapped module path by two level moduleName
781         pos = requestPath.find(PathHelper::SLASH_TAG, pos + 1);
782         if (pos == CString::npos) {
783             return;
784         }
785         moduleName = requestPath.substr(0, pos);
786         isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
787     }
788     if (isModuleName) {
789         // outEntryPoint: @bundle.bundleName/moduleName/Index
790         CString relativePath = requestPath.substr(pos);
791         // get rid of Index, get pure perfix(@bundle.bundleName/moduleName).
792         size_t index = outEntryPoint.rfind(PathHelper::SLASH_TAG);
793         // get rid of src/main. Concat perfix and input relative path.
794         if (relativePath.find(PHYCICAL_FILE_PATH, 0) == 0) {
795             requestPath = base::ConcatToCString(outEntryPoint.substr(0, index), PathHelper::SLASH_TAG,
796                 requestPath.substr(pos + PHYCICAL_FILE_PATH_LEN));
797             return;
798         }
799         requestPath = outEntryPoint.substr(0, index) + requestPath.substr(pos);
800     }
801 }
802 
ParseFileNameToVMAName(const CString & filename)803 CString ModulePathHelper::ParseFileNameToVMAName(const CString &filename)
804 {
805     size_t pos = CString::npos;
806     if (filename.empty()) {
807         return VMA_NAME_ARKTS_CODE.data();
808     }
809 
810     if (filename.find(EXT_NAME_JS) != CString::npos) {
811         pos = filename.find(EXT_NAME_Z_SO);
812         if (pos == CString::npos) {
813             return VMA_NAME_ARKTS_CODE.data();
814         }
815         CString moduleName = filename.substr(0, pos);
816         pos = moduleName.rfind(PathHelper::POINT_TAG);
817         if (pos == CString::npos) {
818             return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, filename);
819         }
820         CString realModuleName = moduleName.substr(pos + 1);
821         CString realFileName = realModuleName;
822         std::transform(realFileName.begin(), realFileName.end(), realFileName.begin(), ::tolower);
823         CString file = base::ConcatToCString(PREFIX_LIB, realFileName, EXT_NAME_Z_SO, PathHelper::SLASH_TAG,
824                                              realModuleName, EXT_NAME_JS);
825         return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, file);
826     }
827 
828     if (filename.find(EXT_NAME_ABC) != CString::npos) {
829         pos = filename.find(BUNDLE_INSTALL_PATH);
830         if (pos == CString::npos) {
831             return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, filename);
832         }
833         CString file = filename.substr(BUNDLE_INSTALL_PATH_LEN);
834         return base::ConcatToCString(VMA_NAME_ARKTS_CODE, PathHelper::COLON_TAG, file);
835     }
836 
837     return VMA_NAME_ARKTS_CODE.data();
838 }
839 
GetPkgContextInfoListElements(EcmaVM * vm,const CString & moduleName,const CString & packageName)840 CVector<CString> ModulePathHelper::GetPkgContextInfoListElements(EcmaVM *vm, const CString &moduleName,
841                                                                  const CString &packageName)
842 {
843     CVector<CString> resultList;
844     if (packageName.empty()) {
845         return resultList;
846     }
847     CMap<CString, CMap<CString, CVector<CString>>> pkgContextList = vm->GetPkgContextInfoList();
848     if (pkgContextList.find(moduleName) == pkgContextList.end()) {
849         return resultList;
850     }
851     CMap<CString, CVector<CString>> pkgList = pkgContextList[moduleName];
852     if (pkgList.find(packageName) == pkgList.end()) {
853         return resultList;
854     }
855     resultList = pkgList[packageName];
856     return resultList;
857 }
858 
ConcatImportFileNormalizedOhmurl(const CString & recordPath,const CString & requestName,const CString & version)859 CString ModulePathHelper::ConcatImportFileNormalizedOhmurl(const CString &recordPath, const CString &requestName,
860     const CString &version)
861 {
862     return base::ConcatToCString(recordPath, requestName, PathHelper::NORMALIZED_OHMURL_TAG, version);
863 }
864 
ConcatNativeSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & version)865 CString ModulePathHelper::ConcatNativeSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
866     const CString &pkgName, const CString &version)
867 {
868     return base::ConcatToCString(PREFIX_NORMALIZED_SO, PathHelper::NORMALIZED_OHMURL_TAG, moduleName,
869         PathHelper::NORMALIZED_OHMURL_TAG, bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgName,
870         PathHelper::NORMALIZED_OHMURL_TAG, version);
871 }
872 
ConcatNotSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & entryPath,const CString & version)873 CString ModulePathHelper::ConcatNotSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
874     const CString &pkgName, const CString &entryPath, const CString &version)
875 {
876     return base::ConcatToCString(PREFIX_NORMALIZED_NOT_SO, PathHelper::NORMALIZED_OHMURL_TAG, moduleName,
877         PathHelper::NORMALIZED_OHMURL_TAG, bundleName, PathHelper::NORMALIZED_OHMURL_TAG, pkgName,
878         PathHelper::SLASH_TAG, entryPath, PathHelper::NORMALIZED_OHMURL_TAG, version);
879 }
880 
NeedTranslateToNormalized(const CString & requestName)881 bool ModulePathHelper::NeedTranslateToNormalized(const CString &requestName)
882 {
883     // if start with @normalized:xxx @native:xxx.xxx @ohos:xxx
884     // no translation is required
885     if (StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED) ||
886         (requestName[0] == PathHelper::NAME_SPACE_TAG &&
887          requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
888             return false;
889     }
890     return true;
891 }
892 
TranslateExpressionToNormalized(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,CString & requestPath)893 CString ModulePathHelper::TranslateExpressionToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
894     [[maybe_unused]] CString &baseFileName, const CString &recordName, CString &requestPath)
895 {
896     if (!NeedTranslateToNormalized(requestPath)) {
897         return requestPath;
898     }
899     if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
900         return StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
901     }
902     EcmaVM *vm = thread->GetEcmaVM();
903     CString inputPath = requestPath;
904     if (IsImportFile(requestPath)) {
905         CString entryPoint = ConcatImportFileNormalizedOhmurlWithRecordName(thread, jsPandaFile, baseFileName,
906             recordName, requestPath);
907         if (entryPoint.empty()) {
908             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
909         }
910     } else if (StringHelper::StringStartWith(requestPath, PREFIX_ETS)) {
911         size_t pos = recordName.find(PREFIX_ETS);
912         if (pos != CString::npos) {
913             requestPath = ConcatImportFileNormalizedOhmurl(recordName.substr(0, pos), requestPath);
914         }
915         if (!jsPandaFile->HasRecord(requestPath)) {
916             THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
917         }
918     } else {
919         ConcatOtherNormalizedOhmurl(vm, jsPandaFile, baseFileName, requestPath);
920     }
921     return requestPath;
922 }
923 
924 /*
925  * Before: requestPath: 1. @ohos.xxx
926  *                      2. har or har/xxx/xxx
927  *                      3. hsp or hsp/xxx/xxx
928  *                      4. libentry.so
929  * After:  requestPath: 1. @ohos:xxx or @native:xxx.xxx
930  *                      2. @normalized:N&moduleName&bundleName&entryPath&version
931  *                      3. @normalized:N&moduleName&bundleName&entryPath&
932  *                      4. @normalized:Y&&bundleName&entryPath&version
933  */
ConcatOtherNormalizedOhmurl(EcmaVM * vm,const JSPandaFile * jsPandaFile,const CString & baseFileName,CString & requestPath)934 void ModulePathHelper::ConcatOtherNormalizedOhmurl(EcmaVM *vm, const JSPandaFile *jsPandaFile,
935     [[maybe_unused]] const CString &baseFileName, CString &requestPath)
936 {
937     CString currentModuleName = GetModuleNameWithBaseFile(baseFileName);
938     CString pkgName = vm->GetPkgNameWithAlias(requestPath);
939     CVector<CString> data = GetPkgContextInfoListElements(vm, currentModuleName, pkgName);
940     if (!data.empty()) {
941         CString entryPath;
942         requestPath = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
943         return;
944     }
945     // When requestName contains '/', it is considered to be a file path.
946     CString result;
947     size_t filePathPos = requestPath.find(PathHelper::SLASH_TAG);
948     if (filePathPos != CString::npos) {
949         result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
950         // Try to get the PkgContextInfo by two levels alias
951         if (result.empty()) {
952             filePathPos = requestPath.find(PathHelper::SLASH_TAG, filePathPos + 1);
953             if (filePathPos != CString::npos) {
954                 result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
955             }
956         }
957     }
958     if (result.empty()) {
959         CString outEntryPoint;
960         if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
961             requestPath = outEntryPoint;
962         }
963         ChangeTag(requestPath);
964         return;
965     }
966     requestPath = result;
967 }
968 
ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM * vm,size_t filePathPos,const CString & moduleName,const CString & requestPath)969 CString ModulePathHelper::ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM *vm, size_t filePathPos,
970     const CString &moduleName, const CString &requestPath)
971 {
972     CString result;
973     CString alias = requestPath.substr(0, filePathPos);
974     CString entryPath = requestPath.substr(filePathPos + 1);
975     CString pkgName = vm->GetPkgNameWithAlias(alias);
976     CVector<CString> data = GetPkgContextInfoListElements(vm, moduleName, pkgName);
977     if (!data.empty()) {
978         result = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
979     }
980     return result;
981 }
982 
ConcatNormalizedOhmurlWithData(const CVector<CString> & data,const CString & pkgName,CString & entryPath)983 CString ModulePathHelper::ConcatNormalizedOhmurlWithData(const CVector<CString> &data, const CString &pkgName,
984     CString &entryPath)
985 {
986     const CString &bundleName = data[PKGINFO_BUDNLE_NAME_INDEX];
987     const CString &moduleName = data[PKGINFO_MODULE_NAME_INDEX];
988     const CString &version = data[PKGINFO_VERSION_INDEX];
989     if (entryPath.empty()) {
990         entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
991     }
992     const CString &isSO = data[PKGINFO_IS_SO_INDEX];
993     if (entryPath.find(PathHelper::CURRENT_DIREATORY_TAG) == 0) {
994         entryPath = entryPath.substr(CURRENT_DIREATORY_TAG_LEN);
995     }
996     if (isSO == TRUE_FLAG) {
997         return ConcatNativeSoNormalizedOhmurl(moduleName, bundleName, pkgName, version);
998     } else {
999         entryPath = RemoveSuffix(entryPath);
1000         return ConcatNotSoNormalizedOhmurl(moduleName, bundleName, pkgName, entryPath, version);
1001     }
1002 }
1003 
TranslateNapiFileRequestPath(JSThread * thread,const CString & modulePath,const CString & requestName)1004 CString ModulePathHelper::TranslateNapiFileRequestPath(JSThread *thread, const CString &modulePath,
1005     const CString &requestName)
1006 {
1007     if (thread->GetEcmaVM()->IsNormalizedOhmUrlPack()) {
1008         CString moduleName = GetModuleNameWithPath(modulePath);
1009         CString res(1, PathHelper::NORMALIZED_OHMURL_TAG);
1010         base::AppendToBaseString(res, moduleName, PHYCICAL_FILE_PATH,
1011             PathHelper::SLASH_TAG, requestName, PathHelper::NORMALIZED_OHMURL_TAG);
1012         return res;
1013     } else {
1014         return base::ConcatToCString(modulePath, PathHelper::SLASH_TAG, requestName);
1015     }
1016 }
1017 
SplitNormalizedOhmurl(const CString & ohmurl)1018 CVector<CString> ModulePathHelper::SplitNormalizedOhmurl(const CString &ohmurl)
1019 {
1020     CVector<CString> res;
1021     size_t start = 0;
1022     size_t pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG);
1023     while (pos != CString::npos) {
1024         CString element = ohmurl.substr(start, pos - start);
1025         res.emplace_back(element);
1026         start = pos + 1;
1027         pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG, start);
1028     }
1029     CString tail = ohmurl.substr(start);
1030     res.emplace_back(tail);
1031     return res;
1032 }
1033 
SplitNormalizedRecordName(const CString & recordName)1034 CVector<CString> ModulePathHelper::SplitNormalizedRecordName(const CString &recordName)
1035 {
1036     CVector<CString> res(NORMALIZED_OHMURL_ARGS_NUM);
1037     int index = NORMALIZED_OHMURL_ARGS_NUM - 1;
1038     CString temp;
1039     int endIndex = static_cast<int>(recordName.size()) - 1;
1040     for (int i = endIndex; i >= 0; i--) {
1041         char element = recordName[i];
1042         if (element == PathHelper::NORMALIZED_OHMURL_TAG) {
1043             res[index] = temp;
1044             index--;
1045             temp = "";
1046             continue;
1047         }
1048         temp = element + temp;
1049     }
1050     if (!temp.empty()) {
1051         res[index] = temp;
1052     }
1053     return res;
1054 }
1055 
1056 /*
1057  * Before: 1. bundleName/moduleName/xxx/xxx
1058            2. bunldeName&moduleName/xxx/xxx&
1059  * After:  bundleName
1060  */
GetBundleNameWithRecordName(EcmaVM * vm,const CString & recordName)1061 CString ModulePathHelper::GetBundleNameWithRecordName(EcmaVM *vm, const CString &recordName)
1062 {
1063     CString bundleName;
1064     if (vm->IsNormalizedOhmUrlPack()) {
1065         CVector<CString> res = ModulePathHelper::SplitNormalizedRecordName(recordName);
1066         bundleName = res[ModulePathHelper::NORMALIZED_BUNDLE_NAME_INDEX];
1067         if (bundleName.empty()) {
1068             bundleName = vm->GetBundleName();
1069         }
1070     } else {
1071         size_t pos = recordName.find(PathHelper::SLASH_TAG);
1072         bundleName = recordName.substr(0, pos);
1073     }
1074     return bundleName;
1075 }
1076 
1077 // this function convert for ESModule name string(Utf8)
Utf8ConvertToString(JSTaggedValue str)1078 CString ModulePathHelper::Utf8ConvertToString(JSTaggedValue str)
1079 {
1080     return EcmaStringAccessor(str).Utf8ConvertToString();
1081 }
1082 
1083 // check if input is ohmurl's ets/ts/js
IsOhmUrl(const CString & str)1084 bool ModulePathHelper::IsOhmUrl(const CString &str)
1085 {
1086     if (StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_BUNDLE) ||
1087         StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_PACKAGE) ||
1088         StringHelper::StringStartWith(str, ModulePathHelper::PREFIX_NORMALIZED_NOT_SO)) {
1089         return true;
1090     }
1091     return false;
1092 }
1093 
CheckAndGetRecordName(JSThread * thread,const CString & ohmUrl,CString & recordName)1094 bool ModulePathHelper::CheckAndGetRecordName(JSThread *thread, const CString &ohmUrl, CString &recordName)
1095 {
1096     if (StringHelper::StringStartWith(ohmUrl, PREFIX_BUNDLE)) {
1097         recordName = ohmUrl.substr(PREFIX_BUNDLE_LEN);
1098         return true;
1099     } else if (StringHelper::StringStartWith(ohmUrl, PREFIX_PACKAGE)) {
1100         recordName = ohmUrl.substr(PREFIX_PACKAGE_LEN);
1101         return true;
1102     } else if (StringHelper::StringStartWith(ohmUrl, PREFIX_NORMALIZED_NOT_SO)) {
1103         CString str;
1104         recordName = ModulePathHelper::ParseNormalizedOhmUrl(thread, str, " ", ohmUrl);
1105         return true;
1106     }
1107     LOG_ECMA(ERROR) << "the requested OhmUrl: '" + ohmUrl +
1108         ", doesn't match current OhmUrl rule, please check build result.";
1109     return false;
1110 }
1111 
1112 /*
1113  * Before: ABC: /data/storage/el1/bundle/xxx/xxx/xxx.abc
1114  * Before: ETS_MODULES: /data/storage/el1/bundle/xxx/ets/modules.abc
1115  */
ValidateAbcPath(const CString & baseFileName,ValidateFilePath checkMode)1116 bool ModulePathHelper::ValidateAbcPath(const CString &baseFileName, ValidateFilePath checkMode)
1117 {
1118     if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
1119         baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
1120         if (checkMode == ValidateFilePath::ETS_MODULES &&
1121             baseFileName.rfind(MERGE_ABC_ETS_MODULES) != CString::npos) {
1122             return true;
1123         }
1124         if (checkMode == ValidateFilePath::ABC &&
1125             baseFileName.rfind(ABC) != CString::npos) {
1126             return true;
1127         }
1128     }
1129     return false;
1130 }
1131 }  // namespace panda::ecmascript