2023-06-23 15:30:55 +00:00
|
|
|
#include "StarAssetPath.hpp"
|
|
|
|
#include "StarLexicalCast.hpp"
|
|
|
|
|
|
|
|
namespace Star {
|
|
|
|
|
|
|
|
// The filename is everything after the last slash (excluding directives) and
|
|
|
|
// up to the first directive marker.
|
|
|
|
static Maybe<pair<size_t, size_t>> findFilenameRange(std::string const& pathUtf8) {
|
|
|
|
size_t firstDirectiveOrSubPath = pathUtf8.find_first_of(":?");
|
|
|
|
size_t filenameStart = 0;
|
|
|
|
while (true) {
|
|
|
|
size_t find = pathUtf8.find('/', filenameStart);
|
|
|
|
if (find >= firstDirectiveOrSubPath)
|
|
|
|
break;
|
|
|
|
filenameStart = find + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filenameStart == NPos) {
|
|
|
|
return {};
|
|
|
|
} else if (firstDirectiveOrSubPath == NPos) {
|
|
|
|
return {{filenameStart, pathUtf8.size()}};
|
|
|
|
} else {
|
|
|
|
return {{filenameStart, firstDirectiveOrSubPath}};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AssetPath AssetPath::split(String const& path) {
|
|
|
|
AssetPath components;
|
|
|
|
|
2023-06-26 15:04:58 +00:00
|
|
|
std::string const& str = path.utf8();
|
2023-06-23 15:30:55 +00:00
|
|
|
|
2023-06-26 15:04:58 +00:00
|
|
|
//base paths cannot have any ':' or '?' characters, stop at the first one.
|
|
|
|
size_t end = str.find_first_of(":?");
|
|
|
|
components.basePath = str.substr(0, end);
|
|
|
|
|
|
|
|
if (end == NPos)
|
|
|
|
return components;
|
2023-06-23 15:30:55 +00:00
|
|
|
|
|
|
|
// Sub-paths must immediately follow base paths and must start with a ':',
|
|
|
|
// after this point any further ':' characters are not special.
|
2023-06-26 15:04:58 +00:00
|
|
|
if (str[end] == ':') {
|
2023-06-26 17:38:57 +00:00
|
|
|
size_t beg = end + 1;
|
|
|
|
if (beg != str.size()) {
|
2024-03-15 10:28:11 +00:00
|
|
|
end = str.find_first_of('?', beg);
|
2023-06-26 17:38:57 +00:00
|
|
|
if (end == NPos && beg + 1 != str.size())
|
|
|
|
components.subPath.emplace(str.substr(beg));
|
|
|
|
else if (size_t len = end - beg)
|
|
|
|
components.subPath.emplace(str.substr(beg, len));
|
|
|
|
}
|
2023-06-23 15:30:55 +00:00
|
|
|
}
|
|
|
|
|
2023-06-26 15:04:58 +00:00
|
|
|
if (end == NPos)
|
|
|
|
return components;
|
|
|
|
|
2023-06-23 15:30:55 +00:00
|
|
|
// Directives must follow the base path and optional sub-path, and each
|
|
|
|
// directive is separated by one or more '?' characters.
|
2023-06-26 15:04:58 +00:00
|
|
|
if (str[end] == '?')
|
|
|
|
components.directives = String(str.substr(end));
|
2023-06-23 15:30:55 +00:00
|
|
|
|
|
|
|
return components;
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::join(AssetPath const& components) {
|
|
|
|
return toString(components);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::setSubPath(String const& path, String const& subPath) {
|
|
|
|
auto components = split(path);
|
|
|
|
components.subPath = subPath;
|
|
|
|
return join(components);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::removeSubPath(String const& path) {
|
|
|
|
auto components = split(path);
|
|
|
|
components.subPath.reset();
|
|
|
|
return join(components);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::getDirectives(String const& path) {
|
|
|
|
size_t firstDirective = path.find('?');
|
|
|
|
if (firstDirective == NPos)
|
|
|
|
return {};
|
|
|
|
return path.substr(firstDirective + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::addDirectives(String const& path, String const& directives) {
|
|
|
|
return String::joinWith("?", path, directives);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::removeDirectives(String const& path) {
|
|
|
|
size_t firstDirective = path.find('?');
|
|
|
|
if (firstDirective == NPos)
|
|
|
|
return path;
|
|
|
|
return path.substr(0, firstDirective);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::directory(String const& path) {
|
|
|
|
if (auto p = findFilenameRange(path.utf8())) {
|
|
|
|
return String(path.utf8().substr(0, p->first));
|
|
|
|
} else {
|
|
|
|
return String();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::filename(String const& path) {
|
|
|
|
if (auto p = findFilenameRange(path.utf8())) {
|
|
|
|
return String(path.utf8().substr(p->first, p->second));
|
|
|
|
} else {
|
|
|
|
return String();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::extension(String const& path) {
|
|
|
|
auto file = filename(path);
|
|
|
|
auto lastDot = file.findLast(".");
|
|
|
|
if (lastDot == NPos)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
return file.substr(lastDot + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AssetPath::relativeTo(String const& sourcePath, String const& givenPath) {
|
|
|
|
if (!givenPath.empty() && givenPath[0] == '/')
|
|
|
|
return givenPath;
|
|
|
|
|
|
|
|
auto path = directory(sourcePath);
|
|
|
|
path.append(givenPath);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AssetPath::operator==(AssetPath const& rhs) const {
|
|
|
|
return tie(basePath, subPath, directives) == tie(rhs.basePath, rhs.subPath, rhs.directives);
|
|
|
|
}
|
|
|
|
|
2023-06-24 15:16:40 +00:00
|
|
|
AssetPath::AssetPath(const char* path) {
|
2024-02-19 15:55:19 +00:00
|
|
|
*this = AssetPath::split(path);
|
2023-06-24 15:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-24 03:06:13 +00:00
|
|
|
AssetPath::AssetPath(String const& path) {
|
2024-02-19 15:55:19 +00:00
|
|
|
*this = AssetPath::split(path);
|
2023-06-24 03:06:13 +00:00
|
|
|
}
|
|
|
|
|
2023-06-24 09:41:52 +00:00
|
|
|
AssetPath::AssetPath(String&& basePath, Maybe<String>&& subPath, DirectivesGroup&& directives) {
|
2024-02-19 15:55:19 +00:00
|
|
|
this->basePath = std::move(basePath);
|
|
|
|
this->subPath = std::move(subPath);
|
|
|
|
this->directives = std::move(directives);
|
2023-06-24 09:41:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AssetPath::AssetPath(String const& basePath, Maybe<String> const& subPath, DirectivesGroup const& directives) {
|
|
|
|
this->basePath = basePath;
|
|
|
|
this->subPath = subPath;
|
|
|
|
this->directives = directives;
|
|
|
|
}
|
|
|
|
|
2023-06-23 15:30:55 +00:00
|
|
|
std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) {
|
|
|
|
os << rhs.basePath;
|
|
|
|
if (rhs.subPath) {
|
|
|
|
os << ":";
|
|
|
|
os << *rhs.subPath;
|
|
|
|
}
|
|
|
|
|
2023-06-25 15:42:18 +00:00
|
|
|
rhs.directives.forEach([&](auto const& entry, Directives const& directives) {
|
2023-06-23 15:30:55 +00:00
|
|
|
os << "?";
|
2024-04-21 20:07:59 +00:00
|
|
|
os << entry.string(*directives);
|
2023-06-23 15:30:55 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2023-06-24 12:49:47 +00:00
|
|
|
size_t hash<AssetPath>::operator()(AssetPath const& s) const {
|
|
|
|
return hashOf(s.basePath, s.subPath, s.directives);
|
|
|
|
}
|
|
|
|
|
2023-06-24 15:16:40 +00:00
|
|
|
DataStream& operator>>(DataStream& ds, AssetPath& path) {
|
|
|
|
String string;
|
|
|
|
ds.read(string);
|
|
|
|
|
2024-02-19 15:55:19 +00:00
|
|
|
path = std::move(string);
|
2023-06-24 15:16:40 +00:00
|
|
|
|
|
|
|
return ds;
|
|
|
|
}
|
|
|
|
|
|
|
|
DataStream& operator<<(DataStream& ds, AssetPath const& path) {
|
|
|
|
ds.write(AssetPath::join(path));
|
|
|
|
|
|
|
|
return ds;
|
|
|
|
}
|
|
|
|
|
2023-06-23 15:30:55 +00:00
|
|
|
}
|