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