/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "util/path_util.h" #include using namespace BASE_NS; namespace PathUtil { string NormalizePath(string_view path) { string res; if (path[0] != '/') { res.reserve(path.size() + 1); res.push_back('/'); } else { res.reserve(path.size()); } while (!path.empty()) { if (path[0] == '/') { path = path.substr(1); continue; } auto pos = path.find_first_of("/", 0); string_view sub = path.substr(0, pos); if (sub == ".") { path = path.substr(pos); continue; } else if (sub == "..") { if ((!res.empty()) && (res.back() == '/')) { res.resize(res.size() - 1); } if (auto p = res.find_last_of('/'); string::npos != p) { res.resize(p); } else { res.clear(); } if (pos == string::npos) { res.push_back('/'); break; } } else { res.append(sub); } if (pos == string::npos) { break; } else { res.push_back('/'); } path = path.substr(pos); } return res; } string GetParentPath(string_view path) { const size_t separatorPos = path.rfind('/'); if (separatorPos == string::npos) { return ""; } else { return string(path.substr(0, separatorPos + 1)); } } string ResolvePath(string_view parent, string_view uri, bool allowQueryString) { size_t queryPos = allowQueryString ? string::npos : uri.find('?'); string_view path = (string::npos != queryPos) ? uri.substr(0, queryPos) : uri; if (parent.empty()) { return string(path); } if (path.empty()) { return string(parent); } if (path[0] == '/') { path = path.substr(1); } else if (path.find("://") != path.npos) { return string(path); } // NOTE: Resolve always assumes the parent path is a directory even if there is no '/' in the end if (parent.back() == '/') { return parent + path; } else { return parent + "/" + path; } } string GetRelativePath(string_view path, string_view relativeTo) { // remove the common prefix { int lastSeparator = -1; for (size_t i = 0, iMax = Math::min(path.size(), relativeTo.size()); i < iMax; ++i) { if (path[i] != relativeTo[i]) { break; } if (path[i] == '/') { lastSeparator = int(i); } } const auto lastPos = static_cast(static_cast(lastSeparator) + 1); path.remove_prefix(lastPos); relativeTo.remove_prefix(lastPos); } if (path[1] == ':' && relativeTo[1] == ':' && path[0] != relativeTo[0]) { // files are on different drives return string(path); } // count and remove the directories left in relative_to auto directoriesCount = 0; { auto nextSeparator = relativeTo.find('/'); while (nextSeparator != string::npos) { relativeTo.remove_prefix(nextSeparator + 1); nextSeparator = relativeTo.find('/'); ++directoriesCount; } } string relativePath = ""; for (auto i = 0, iMax = directoriesCount; i < iMax; ++i) { relativePath.append("../"); } relativePath.append(path); return relativePath; } string GetFilename(string_view path) { if (!path.empty() && path[path.size() - 1] == '/') { // Return a name also for folders. path = path.substr(0, path.size() - 1); } size_t cutPos = path.find_last_of("\\/"); if (string::npos != cutPos) { return string(path.substr(cutPos + 1)); } else { return string(path); } } string GetExtension(string_view path) { size_t fileExtCut = path.rfind('.'); if (fileExtCut != string::npos) { size_t queryCut = path.find('?', fileExtCut); if (queryCut != string::npos) { return string(path.substr(fileExtCut + 1, queryCut)); } else { return string(path.substr(fileExtCut + 1, queryCut)); } } return ""; } string GetBaseName(string_view path) { auto filename = GetFilename(path); size_t fileExtCut = filename.rfind("."); if (string::npos != fileExtCut) { filename.erase(fileExtCut); } return filename; } unordered_map GetUriParameters(string_view uri) { const size_t queryPos = uri.find('?'); if (queryPos != string::npos) { unordered_map params; size_t paramStartPos = queryPos; while (paramStartPos < uri.size()) { size_t paramValuePos = uri.find('=', paramStartPos + 1); size_t paramEndPos = uri.find('&', paramStartPos + 1); if (paramEndPos == string::npos) { paramEndPos = uri.size(); } if (paramValuePos != string::npos && paramValuePos < paramEndPos) { auto key = uri.substr(paramStartPos + 1, paramValuePos - paramStartPos - 1); auto value = uri.substr(paramValuePos + 1, paramEndPos - paramValuePos - 1); params[key] = value; } else { auto key = uri.substr(paramStartPos + 1, paramEndPos - paramStartPos - 1); params[key] = key; } paramStartPos = paramEndPos; } return params; } return {}; } string ResolveUri(string_view contextUri, string_view uri, bool allowQueryString) { return ResolvePath(GetParentPath(contextUri), uri, allowQueryString); } } // namespace PathUtil