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