18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "path_tools.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <cstdlib> 198bf80f4bSopenharmony_ci 208bf80f4bSopenharmony_ci#include <base/containers/string.h> 218bf80f4bSopenharmony_ci#include <base/containers/string_view.h> 228bf80f4bSopenharmony_ci#include <core/log.h> 238bf80f4bSopenharmony_ci#include <core/namespace.h> 248bf80f4bSopenharmony_ci 258bf80f4bSopenharmony_ci#include "util/string_util.h" 268bf80f4bSopenharmony_ci 278bf80f4bSopenharmony_ci#if defined(__linux__) || defined(__APPLE__) 288bf80f4bSopenharmony_ci#include <unistd.h> 298bf80f4bSopenharmony_ci#elif defined(_WIN32) 308bf80f4bSopenharmony_ci#include <direct.h> 318bf80f4bSopenharmony_ci#endif 328bf80f4bSopenharmony_ci 338bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE() 348bf80f4bSopenharmony_ciusing BASE_NS::string; 358bf80f4bSopenharmony_ciusing BASE_NS::string_view; 368bf80f4bSopenharmony_ci 378bf80f4bSopenharmony_cibool IsRelative(const string_view path) 388bf80f4bSopenharmony_ci{ 398bf80f4bSopenharmony_ci if (path.empty()) { 408bf80f4bSopenharmony_ci return true; 418bf80f4bSopenharmony_ci } 428bf80f4bSopenharmony_ci return path[0] != '/'; 438bf80f4bSopenharmony_ci} 448bf80f4bSopenharmony_ci 458bf80f4bSopenharmony_cibool ParseUri(string_view uri, string_view& protocol, string_view& path) 468bf80f4bSopenharmony_ci{ 478bf80f4bSopenharmony_ci const size_t index = uri.find(':'); 488bf80f4bSopenharmony_ci if (index != string_view::npos) { 498bf80f4bSopenharmony_ci protocol = uri.substr(0, index); 508bf80f4bSopenharmony_ci // remove scheme and separator 518bf80f4bSopenharmony_ci uri.remove_prefix(index + 1U); 528bf80f4bSopenharmony_ci // remove the authority separator if it's there 538bf80f4bSopenharmony_ci if (uri.starts_with("//")) { 548bf80f4bSopenharmony_ci uri.remove_prefix(2U); 558bf80f4bSopenharmony_ci } 568bf80f4bSopenharmony_ci path = uri; 578bf80f4bSopenharmony_ci return true; 588bf80f4bSopenharmony_ci } 598bf80f4bSopenharmony_ci 608bf80f4bSopenharmony_ci return false; 618bf80f4bSopenharmony_ci} 628bf80f4bSopenharmony_ci 638bf80f4bSopenharmony_cistring NormalizePath(string_view path) 648bf80f4bSopenharmony_ci{ 658bf80f4bSopenharmony_ci if (path.empty()) { 668bf80f4bSopenharmony_ci return "/"; 678bf80f4bSopenharmony_ci } 688bf80f4bSopenharmony_ci string res; 698bf80f4bSopenharmony_ci res.reserve(path.size()); 708bf80f4bSopenharmony_ci res.push_back('/'); 718bf80f4bSopenharmony_ci while (!path.empty()) { 728bf80f4bSopenharmony_ci if (path[0] == '/') { 738bf80f4bSopenharmony_ci path = path.substr(1); 748bf80f4bSopenharmony_ci continue; 758bf80f4bSopenharmony_ci } 768bf80f4bSopenharmony_ci auto pos = path.find_first_of('/', 0); 778bf80f4bSopenharmony_ci if (const string_view sub = path.substr(0, pos); sub == "..") { 788bf80f4bSopenharmony_ci if ((!res.empty()) && (res.back() == '/')) { 798bf80f4bSopenharmony_ci res.resize(res.size() - 1); 808bf80f4bSopenharmony_ci } 818bf80f4bSopenharmony_ci 828bf80f4bSopenharmony_ci if (auto p = res.find_last_of('/'); string::npos != p) { 838bf80f4bSopenharmony_ci res.resize(p); 848bf80f4bSopenharmony_ci } else { 858bf80f4bSopenharmony_ci if (res.empty()) { 868bf80f4bSopenharmony_ci // trying to back out of root. (ie. invalid path) 878bf80f4bSopenharmony_ci return ""; 888bf80f4bSopenharmony_ci } 898bf80f4bSopenharmony_ci res.clear(); 908bf80f4bSopenharmony_ci } 918bf80f4bSopenharmony_ci if (pos == string::npos) { 928bf80f4bSopenharmony_ci res.push_back('/'); 938bf80f4bSopenharmony_ci break; 948bf80f4bSopenharmony_ci } 958bf80f4bSopenharmony_ci } else if (sub == ".") { 968bf80f4bSopenharmony_ci path = path.substr(pos); 978bf80f4bSopenharmony_ci continue; 988bf80f4bSopenharmony_ci } else { 998bf80f4bSopenharmony_ci res.append(sub); 1008bf80f4bSopenharmony_ci } 1018bf80f4bSopenharmony_ci if (pos == string::npos) { 1028bf80f4bSopenharmony_ci break; 1038bf80f4bSopenharmony_ci } 1048bf80f4bSopenharmony_ci res.push_back('/'); 1058bf80f4bSopenharmony_ci path = path.substr(pos); 1068bf80f4bSopenharmony_ci } 1078bf80f4bSopenharmony_ci return res; 1088bf80f4bSopenharmony_ci} 1098bf80f4bSopenharmony_ci 1108bf80f4bSopenharmony_cistring GetCurrentDirectory() 1118bf80f4bSopenharmony_ci{ 1128bf80f4bSopenharmony_ci string basePath; 1138bf80f4bSopenharmony_ci#if defined(__linux__) || defined(__APPLE__) 1148bf80f4bSopenharmony_ci // OSX and linux both implement the "null buf" extension which allocates the required amount of space. 1158bf80f4bSopenharmony_ci auto tmp = getcwd(nullptr, 0); 1168bf80f4bSopenharmony_ci if (tmp) { 1178bf80f4bSopenharmony_ci basePath = tmp; 1188bf80f4bSopenharmony_ci if (basePath.back() != '/') { 1198bf80f4bSopenharmony_ci basePath += '/'; 1208bf80f4bSopenharmony_ci } 1218bf80f4bSopenharmony_ci free(tmp); 1228bf80f4bSopenharmony_ci } else { 1238bf80f4bSopenharmony_ci // fallback to root (either out-of-memory or the CWD is inaccessible for current user) 1248bf80f4bSopenharmony_ci basePath = "/"; 1258bf80f4bSopenharmony_ci CORE_LOG_F("Could not get current working directory, initializing base path as '/'"); 1268bf80f4bSopenharmony_ci } 1278bf80f4bSopenharmony_ci#elif defined(_WIN32) 1288bf80f4bSopenharmony_ci // Windows also implements the "null buf" extension, but uses a different name and "format". 1298bf80f4bSopenharmony_ci auto tmp = _getcwd(nullptr, 0); 1308bf80f4bSopenharmony_ci if (tmp) { 1318bf80f4bSopenharmony_ci basePath = tmp; 1328bf80f4bSopenharmony_ci StringUtil::FindAndReplaceAll(basePath, "\\", "/"); 1338bf80f4bSopenharmony_ci free(tmp); 1348bf80f4bSopenharmony_ci } else { 1358bf80f4bSopenharmony_ci // fallback to root (yes, technically it's the root of current drive, which again can change when ever. 1368bf80f4bSopenharmony_ci // but then again _getcwd should always work, except in out-of-memory cases where this is the least of our 1378bf80f4bSopenharmony_ci // problems. 1388bf80f4bSopenharmony_ci basePath = "/"; 1398bf80f4bSopenharmony_ci CORE_LOG_F("Could not get current working directory, initializing base path as '/'"); 1408bf80f4bSopenharmony_ci } 1418bf80f4bSopenharmony_ci#else 1428bf80f4bSopenharmony_ci // Unsupported platform.fallback to root. 1438bf80f4bSopenharmony_ci basePath = "/"; 1448bf80f4bSopenharmony_ci#endif 1458bf80f4bSopenharmony_ci 1468bf80f4bSopenharmony_ci // Make sure that we end with a slash. 1478bf80f4bSopenharmony_ci if (basePath.back() != '/') { 1488bf80f4bSopenharmony_ci basePath.push_back('/'); 1498bf80f4bSopenharmony_ci } 1508bf80f4bSopenharmony_ci // And make sure we start with a slash also. 1518bf80f4bSopenharmony_ci if (basePath.front() != '/') { 1528bf80f4bSopenharmony_ci basePath.insert(0, "/"); 1538bf80f4bSopenharmony_ci } 1548bf80f4bSopenharmony_ci return basePath; 1558bf80f4bSopenharmony_ci} 1568bf80f4bSopenharmony_ci 1578bf80f4bSopenharmony_ci#if _WIN32 1588bf80f4bSopenharmony_civoid SplitPath(string_view pathIn, string_view& drive, string_view& path, string_view& filename, string_view& ext) 1598bf80f4bSopenharmony_ci{ 1608bf80f4bSopenharmony_ci drive = path = filename = ext = {}; 1618bf80f4bSopenharmony_ci if (pathIn[0] == '/') { 1628bf80f4bSopenharmony_ci // see if there is a drive after 1638bf80f4bSopenharmony_ci if (pathIn[2] == ':') { // 2: index of ':' 1648bf80f4bSopenharmony_ci // yes. 1658bf80f4bSopenharmony_ci // remove the first '/' to help later parsing 1668bf80f4bSopenharmony_ci pathIn = pathIn.substr(1); 1678bf80f4bSopenharmony_ci } 1688bf80f4bSopenharmony_ci } 1698bf80f4bSopenharmony_ci // extract the drive 1708bf80f4bSopenharmony_ci if (pathIn[1] == ':') { 1718bf80f4bSopenharmony_ci drive = pathIn.substr(0, 1); 1728bf80f4bSopenharmony_ci pathIn = pathIn.substr(2); // 2: remove the drive part 1738bf80f4bSopenharmony_ci } 1748bf80f4bSopenharmony_ci auto lastSlash = pathIn.find_last_of('/'); 1758bf80f4bSopenharmony_ci if (lastSlash != string_view::npos) { 1768bf80f4bSopenharmony_ci filename = pathIn.substr(lastSlash + 1); 1778bf80f4bSopenharmony_ci path = pathIn.substr(0, lastSlash + 1); 1788bf80f4bSopenharmony_ci } else { 1798bf80f4bSopenharmony_ci filename = pathIn; 1808bf80f4bSopenharmony_ci } 1818bf80f4bSopenharmony_ci auto lastDot = filename.find_last_of('.'); 1828bf80f4bSopenharmony_ci if (lastDot != string_view::npos) { 1838bf80f4bSopenharmony_ci ext = filename.substr(lastDot + 1); 1848bf80f4bSopenharmony_ci filename = filename.substr(0, lastDot); 1858bf80f4bSopenharmony_ci } 1868bf80f4bSopenharmony_ci} 1878bf80f4bSopenharmony_ci#endif 1888bf80f4bSopenharmony_ciCORE_END_NAMESPACE() 189