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 #ifndef ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H 16 #define ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H 17 18 #include "ecmascript/base/path_helper.h" 19 20 #include "ecmascript/compiler/aot_file/aot_file_manager.h" 21 #include "ecmascript/base/string_helper.h" 22 #include "ecmascript/ecma_macros.h" 23 #include "ecmascript/ecma_string.h" 24 #include "ecmascript/ecma_vm.h" 25 #include "ecmascript/global_env.h" 26 #include "ecmascript/js_tagged_value-inl.h" 27 #include "ecmascript/jspandafile/js_pandafile.h" 28 /* 29 * Intra-application cross hap: 30 * baseFileName = 'data/storage/el1/bundle/moduleName/ets/modules.abc'; 31 * cross-application: 32 * baseFileName = 'data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc'; 33 * recordName = bundleName/moduleName/xxx(entry)/xxx(ets)/xxx(pages)/xxx specific abc file 34 * 35 * ohmUrl: It's an index information that can uniquely identify module files. 36 * Current ohmUrl has the following five different prefixs: 37 * 1. @bundle:... Identify OpenHarmony modules. 38 * {project_path}\entry\src\main\ets\pages\Index --> @bundle:bundleName/moduleName/ets/pages/Index 39 * @namespace: needs to add when import local har or ohosTest import entry file. 40 * {project_path}\namespace\src\main\ets\pages\Index --> @bundle:bundleName/moduleName@namespace/ets/pages/Index 41 * 42 * 2. @package:... Identify open source third party modules. 43 * {project_path}\node_modules.ohpm\pkgName\oh_modules\pkgName\xxx\xxx 44 * --> @package:pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx 45 * 46 * 3. @app:... Identify c++ modules in application. 47 * libxxx.so --> @app:bundleName/moduleName/xxx 48 * 49 * 4. @native:... Identify system builtin modules. 50 * system.app --> @native:system.app 51 * 52 * 5. @ohos:... Identify ohos builtin modules. 53 * @ohos:hilog --> @ohos:hilog 54 */ 55 56 namespace panda::ecmascript { 57 using PathHelper = base::PathHelper; 58 using StringHelper = base::StringHelper; 59 60 enum ValidateFilePath { ABC, ETS_MODULES }; 61 62 class ModulePathHelper { 63 public: 64 static constexpr std::string_view EXT_NAME_ABC = ".abc"; 65 static constexpr std::string_view EXT_NAME_ETS = ".ets"; 66 static constexpr std::string_view EXT_NAME_TS = ".ts"; 67 static constexpr std::string_view EXT_NAME_JS = ".js"; 68 static constexpr std::string_view EXT_NAME_JSON = ".json"; 69 static constexpr std::string_view EXT_NAME_Z_SO = ".z.so"; 70 static constexpr std::string_view EXT_NAME_D_TS = ".d.ts"; 71 static constexpr std::string_view EXT_NAME_MJS = ".mjs"; 72 static constexpr std::string_view EXT_NAME_HQF = ".hqf"; 73 static constexpr std::string_view PREFIX_NORMALIZED = "@normalized:"; 74 static constexpr std::string_view PREFIX_NORMALIZED_SO = "@normalized:Y"; 75 static constexpr std::string_view PREFIX_NORMALIZED_NOT_SO = "@normalized:N"; 76 static constexpr std::string_view PREFIX_NORMALIZED_NOT_CROSS_HAP_FILE = "@normalized:N&&&"; 77 static constexpr std::string_view PREFIX_BUNDLE = "@bundle:"; 78 static constexpr std::string_view PREFIX_MODULE = "@module:"; 79 static constexpr std::string_view PREFIX_PACKAGE = "@package:"; 80 static constexpr std::string_view PREFIX_ETS = "ets/"; 81 static constexpr std::string_view PREFIX_LIB = "lib"; 82 static constexpr std::string_view REQUIRE_NAITVE_MODULE_PREFIX = "@native:"; 83 static constexpr std::string_view REQUIRE_NAPI_OHOS_PREFIX = "@ohos:"; 84 static constexpr std::string_view REQUIRE_NAPI_APP_PREFIX = "@app:"; 85 static constexpr std::string_view RAW_ARKUIX_PREFIX = "@arkui-x."; 86 static constexpr std::string_view NPM_PATH_SEGMENT = "node_modules"; 87 static constexpr std::string_view PACKAGE_PATH_SEGMENT = "pkg_modules"; 88 static constexpr std::string_view PACKAGE_ENTRY_FILE = "/index"; 89 static constexpr std::string_view BUNDLE_INSTALL_PATH = "/data/storage/el1/bundle/"; 90 static constexpr std::string_view MERGE_ABC_ETS_MODULES = "/ets/modules.abc"; 91 static constexpr std::string_view ABC = ".abc"; 92 static constexpr std::string_view MODULE_DEFAULE_ETS = "/ets/"; 93 static constexpr std::string_view BUNDLE_SUB_INSTALL_PATH = "/data/storage/el1/"; 94 static constexpr std::string_view PREVIEW_OF_ACROSS_HAP_FLAG = "[preview]"; 95 static constexpr std::string_view PREVIER_TEST_DIR = ".test"; 96 static constexpr std::string_view PHYCICAL_FILE_PATH = "/src/main"; 97 static constexpr std::string_view VMA_NAME_ARKTS_CODE = "ArkTS Code"; 98 static constexpr std::string_view ENTRY_MAIN_FUNCTION = "_GLOBAL::func_main_0"; 99 static constexpr std::string_view ENTRY_FUNCTION_NAME = "func_main_0"; 100 static constexpr std::string_view TRUE_FLAG = "true"; 101 102 static constexpr size_t MAX_PACKAGE_LEVEL = 1; 103 static constexpr size_t SEGMENTS_LIMIT_TWO = 2; 104 static constexpr size_t EXT_NAME_ABC_LEN = 4; 105 static constexpr size_t EXT_NAME_ETS_LEN = 4; 106 static constexpr size_t EXT_NAME_TS_LEN = 3; 107 static constexpr size_t EXT_NAME_JS_LEN = 3; 108 static constexpr size_t EXT_NAME_JSON_LEN = 5; 109 static constexpr size_t PREFIX_BUNDLE_LEN = 8; 110 static constexpr size_t PREFIX_MODULE_LEN = 8; 111 static constexpr size_t PREFIX_PACKAGE_LEN = 9; 112 static constexpr size_t PREFIX_NORMALIZED_LEN = 15; 113 static constexpr size_t PACKAGE_PATH_SEGMENT_LEN = 11; 114 static constexpr size_t NATIVE_PREFIX_SIZE = 8; 115 static constexpr size_t OHOS_PREFIX_SIZE = 6; 116 static constexpr size_t APP_PREFIX_SIZE = 5; 117 static constexpr size_t BUNDLE_INSTALL_PATH_LEN = 25; 118 static constexpr size_t PHYCICAL_FILE_PATH_LEN = 10; 119 static constexpr size_t NORMALIZED_OHMURL_ARGS_NUM = 5; 120 static constexpr size_t NORMALIZED_MODULE_NAME_INDEX = 1; 121 static constexpr size_t NORMALIZED_BUNDLE_NAME_INDEX = 2; 122 static constexpr size_t NORMALIZED_IMPORT_PATH_INDEX = 3; 123 static constexpr size_t NORMALIZED_VERSION_INDEX = 4; 124 static constexpr size_t CURRENT_DIREATORY_TAG_LEN = 2; 125 static constexpr size_t SO_PREFIX_LEN = 3; 126 static constexpr size_t SO_SUFFIX_LEN = 3; 127 128 static constexpr size_t PKGINFO_PACKAGE_NAME_INDEX = 1; 129 static constexpr size_t PKGINFO_BUDNLE_NAME_INDEX = 3; 130 static constexpr size_t PKGINFO_MODULE_NAME_INDEX = 5; 131 static constexpr size_t PKGINFO_VERSION_INDEX = 7; 132 static constexpr size_t PKGINFO_ENTRY_PATH_INDEX = 9; 133 static constexpr size_t PKGINFO_IS_SO_INDEX = 11; 134 135 static CString PUBLIC_API ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, 136 CString &baseFileName, const CString &recordName, const CString &requestName); 137 static void ParseAbcPathAndOhmUrl(EcmaVM *vm, const CString &inputFileName, CString &outBaseFileName, 138 CString &outEntryPoint); 139 static CString ConcatUnifiedOhmUrl(const CString &bundleName, const CString &pkgname, const CString &entryPath, 140 const CString &path, const CString &version); 141 static CString ConcatUnifiedOhmUrl(const CString &bundleName, const CString &normalizedpath, 142 const CString &version); 143 static CString ConcatPreviewTestUnifiedOhmUrl(const CString &bundleName, const CString &pkgname, 144 const CString &path, const CString &version); 145 static CString ConcatHspFileNameCrossBundle(const CString &bundleName, const CString &moduleName); 146 static CString ConcatHspFileName(const CString &moduleName); 147 static CString ThrowInvalidOhmurlError(EcmaVM *vm, const CString &oldEntryPoint); 148 static CString TransformToNormalizedOhmUrl(EcmaVM *vm, const CString &inputFileName, const CString &baseFileName, 149 const CString &oldEntryPoint); 150 static CString ParseUrl(EcmaVM *vm, const CString &recordName); 151 static CString ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile, 152 [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName); 153 static CString ParseNormalizedOhmUrl(JSThread *thread, CString &baseFileName, const CString &recordName, 154 CString requestName); 155 static CString MakeNewRecord(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName, 156 const CString &recordName, const CString &requestName); 157 static CString FindOhpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &ohpmPath, 158 const CString &requestName); 159 static CString FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile, const CString &requestName, 160 const CString &recordName); 161 static CString ParseOhpmPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 162 const CString &requestName); 163 static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 164 const CString &requestName, const CString &packagePath); 165 static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 166 const CString &requestName); 167 static void ResolveCurrentPath(CString &dirPath, CString &fileName, const JSPandaFile *jsPandaFile); 168 static CString FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint); 169 static CString FindPackageInTopLevel(const JSPandaFile *jsPandaFile, const CString &requestName, 170 const CString &packagePath); 171 static bool IsImportFile(const CString &moduleRequestName); 172 static CString RemoveSuffix(const CString &requestName); 173 static bool NeedTranstale(const CString &requestName); 174 static bool NeedTranslateToNormalized(const CString &requestName); 175 static void TranstaleExpressionInput(const JSPandaFile *jsPandaFile, CString &requestPath); 176 static CString GetModuleNameWithBaseFile(const CString &baseFileName); 177 static CString TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile, 178 const CString &baseFileName, const CString &requestName); 179 static void ParseCrossModuleFile(const JSPandaFile *jsPandaFile, CString &requestPath); 180 static CString ReformatPath(const CString& requestName); 181 static CString TranslateExpressionToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile, 182 [[maybe_unused]] CString &baseFileName, const CString &recordName, 183 CString &requestPath); 184 static CVector<CString> GetPkgContextInfoListElements(EcmaVM *vm, const CString &moduleName, 185 const CString &packageName); 186 static CString TranslateNapiFileRequestPath(JSThread *thread, const CString &modulePath, 187 const CString &requestName); 188 static CVector<CString> SplitNormalizedOhmurl(const CString &ohmurl); 189 static CString ConcatImportFileNormalizedOhmurl(const CString &recordPath, const CString &requestName, 190 const CString &version = ""); 191 static CString ConcatNativeSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName, 192 const CString &pkgName, const CString &version); 193 static CString ConcatNotSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName, 194 const CString &pkgName, const CString &entryPath, 195 const CString &version); 196 static CString ConcatMergeFileNameToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile, 197 CString &baseFileName, const CString &recordName, 198 CString requestName); 199 static CVector<CString> SplitNormalizedRecordName(const CString &recordName); 200 static CString ConcatImportFileNormalizedOhmurlWithRecordName(JSThread *thread, const JSPandaFile *jsPandaFile, 201 CString &baseFileName, const CString &recordName, 202 const CString &requestName); 203 static void ConcatOtherNormalizedOhmurl(EcmaVM *vm, const JSPandaFile *jsPandaFile, 204 [[maybe_unused]] const CString &baseFileName, CString &requestPath); 205 static CString ConcatNormalizedOhmurlWithData(const CVector<CString> &data, const CString &pkgName, 206 CString &entryPath); 207 static CString GetBundleNameWithRecordName(EcmaVM *vm, const CString &recordName); 208 static CString Utf8ConvertToString(JSThread *thread, JSTaggedValue str); 209 210 static CString ParseFileNameToVMAName(const CString &filename); 211 static CString ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM *vm, size_t filePathPos, const CString &moduleName, 212 const CString &requestPath); 213 static bool IsOhmUrl(const CString &str); 214 static bool CheckAndGetRecordName(JSThread *thread, const CString &ohmUrl, CString &recordName); 215 static bool ValidateAbcPath(const CString &baseFileName, ValidateFilePath checkMode); 216 static std::pair<std::string, std::string> ResolveOhmUrl(std::string ohmUrl); 217 static std::pair<std::string, std::string> ResolveOhmUrlStartWithBundle(const std::string &ohmUrl); 218 static std::pair<std::string, std::string> ResolveOhmUrlStartWithNormalized(const std::string &ohmUrl); 219 ResolvePath(const char * path)220 inline static std::pair<CString, CString> ResolvePath(const char *path) 221 { 222 CString filePath(path); 223 size_t index = filePath.find_last_of('/'); 224 if (index == std::string::npos) { 225 LOG_FULL(FATAL) << "The OhmUrl is invalid"; 226 } 227 CString entry = filePath.substr(index + 1); 228 return {filePath + ABC.data(), entry}; 229 } 230 231 /* 232 * Before: /data/storage/el1/bundle/moduleName/ets/modules.abc 233 * After: bundle/moduleName 234 */ ParseHapPath(const CString & baseFileName)235 inline static std::string ParseHapPath(const CString &baseFileName) 236 { 237 CString bundleSubInstallName(BUNDLE_SUB_INSTALL_PATH); 238 size_t startStrLen = bundleSubInstallName.length(); 239 if (baseFileName.length() > startStrLen && baseFileName.compare(0, startStrLen, bundleSubInstallName) == 0) { 240 CString hapPath = baseFileName.substr(startStrLen); 241 size_t pos = hapPath.find(MERGE_ABC_ETS_MODULES); 242 if (pos != CString::npos) { 243 return hapPath.substr(0, pos).c_str(); 244 } 245 } 246 return {}; 247 } 248 249 /* 250 * Before: xxx 251 * After: xxx || xxx/index 252 */ ConfirmLoadingIndexOrNot(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)253 inline static CString ConfirmLoadingIndexOrNot(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint) 254 { 255 CString entryPoint = packageEntryPoint; 256 if (jsPandaFile->HasRecord(entryPoint)) { 257 return entryPoint; 258 } 259 // Possible import directory 260 entryPoint += PACKAGE_ENTRY_FILE; 261 entryPoint = PathHelper::NormalizePath(entryPoint); 262 if (jsPandaFile->HasRecord(entryPoint)) { 263 return entryPoint; 264 } 265 return {}; 266 } 267 IsNativeModuleRequest(const CString & requestName)268 inline static bool IsNativeModuleRequest(const CString &requestName) 269 { 270 if (requestName[0] != PathHelper::NAME_SPACE_TAG) { 271 return false; 272 } 273 if (StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAPI_OHOS_PREFIX) || 274 StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAPI_APP_PREFIX) || 275 StringHelper::StringStartWith(requestName, ModulePathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) { 276 return true; 277 } 278 return false; 279 } 280 281 /* 282 * Before: bundleName/moduleName/ets/xxx/xxx 283 * After: moduleName 284 */ GetModuleName(const CString & recordName)285 inline static CString GetModuleName(const CString& recordName) 286 { 287 if (size_t pos1 = recordName.find(PathHelper::SLASH_TAG); pos1 != CString::npos) { 288 pos1++; 289 if (const size_t pos2 = recordName.find(PathHelper::SLASH_TAG, pos1); pos2 != CString::npos) { 290 CString moduleName = recordName.substr(pos1, pos2 - pos1); 291 PathHelper::DeleteNamespace(moduleName); 292 return moduleName; 293 } 294 } 295 return {}; 296 } 297 298 /* 299 * Before: &moduleName/src/xxx 300 * After: moduleName 301 */ GetModuleNameWithNormalizedName(const CString & recordName)302 inline static CString GetModuleNameWithNormalizedName(const CString& recordName) 303 { 304 size_t pos1 = recordName.find(PathHelper::NORMALIZED_OHMURL_TAG); 305 if (pos1 != CString::npos) { 306 pos1++; 307 size_t pos2 = recordName.find(PathHelper::SLASH_TAG, pos1); 308 if (pos2 != CString::npos) { 309 CString moduleName = recordName.substr(pos1, pos2 - pos1); 310 return moduleName; 311 } 312 } 313 return {}; 314 } 315 316 /* 317 * Before: bundleName/moduleName 318 * After: moduleName 319 */ GetModuleNameWithPath(const CString & modulePath)320 inline static CString GetModuleNameWithPath(const CString& modulePath) 321 { 322 size_t pos1 = modulePath.find(PathHelper::SLASH_TAG); 323 if (pos1 != CString::npos) { 324 pos1++; 325 return modulePath.substr(pos1, modulePath.size() - pos1 + 1); 326 } 327 return {}; 328 } 329 /* 330 * Before: @xxx. 331 * After: @xxx: 332 */ ChangeTag(CString & path)333 inline static bool ChangeTag(CString &path) 334 { 335 if (path[0] == PathHelper::NAME_SPACE_TAG) { 336 size_t pos = path.find(PathHelper::POINT_TAG); 337 if (pos != CString::npos) { 338 path.replace(pos, 1, PathHelper::COLON_TAG); // 1: length 339 return true; 340 } 341 } 342 return false; 343 } 344 345 /* 346 * Before: moduleName 347 * After: data/storage/el1/bundle/moduleName/ets/modules.abc 348 */ ConcatPandaFilePath(const CString & moduleName)349 inline static CString ConcatPandaFilePath(const CString &moduleName) 350 { 351 if (moduleName.empty()) { 352 return {}; 353 } 354 return base::ConcatToCString(BUNDLE_INSTALL_PATH, moduleName, MERGE_ABC_ETS_MODULES); 355 } 356 GetBundleNameFromNormalized(const EcmaVM * vm,const CString & moduleName)357 inline static CString GetBundleNameFromNormalized(const EcmaVM *vm, const CString &moduleName) 358 { 359 CVector<CString> res = SplitNormalizedOhmurl(moduleName); 360 if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) { 361 LOG_FULL(ERROR) << "GetBundleNameFromNormalized Invalid normalized ohmurl"; 362 return ""; 363 } 364 CString bundleName = res[NORMALIZED_BUNDLE_NAME_INDEX]; 365 if (bundleName.empty()) { 366 return vm->GetBundleName(); 367 } 368 return bundleName; 369 } 370 GetNormalizedPathFromOhmUrl(const CString & moduleName)371 inline static CString GetNormalizedPathFromOhmUrl(const CString &moduleName) 372 { 373 CVector<CString> res = SplitNormalizedOhmurl(moduleName); 374 if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) { 375 LOG_FULL(ERROR) << "GetNormalizedPathFromOhmUrl Invalid normalized ohmurl"; 376 return ""; 377 } 378 CString soName = res[NORMALIZED_IMPORT_PATH_INDEX]; 379 // Delete the prefix "lib" and suffix ".so". 380 soName = soName.substr(SO_PREFIX_LEN, soName.size() - SO_PREFIX_LEN - SO_SUFFIX_LEN); 381 return soName; 382 } 383 }; 384 } // namespace panda::ecmascript 385 #endif // ECMASCRIPT_MODULE_MODULE_PATH_HELPER_H