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