97 lines
2.5 KiB
C++
97 lines
2.5 KiB
C++
#include "stdafx.h"
|
|
#include "ShaderUiPath.h"
|
|
|
|
namespace ShaderUiPath
|
|
{
|
|
namespace
|
|
{
|
|
bool IsPathUnderRoot(const std::filesystem::path& root, const std::filesystem::path& path)
|
|
{
|
|
std::error_code errorCode;
|
|
const std::filesystem::path canonicalRoot = std::filesystem::weakly_canonical(root, errorCode);
|
|
if (errorCode)
|
|
return false;
|
|
|
|
const std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(path, errorCode);
|
|
if (errorCode)
|
|
return false;
|
|
|
|
const std::filesystem::path relative = canonicalPath.lexically_relative(canonicalRoot);
|
|
if (relative.empty() || relative.is_absolute())
|
|
return false;
|
|
for (const std::filesystem::path& part : relative)
|
|
{
|
|
if (part == "..")
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool NormalizeAssetPath(const std::string& assetPath, std::filesystem::path& normalizedPath)
|
|
{
|
|
normalizedPath.clear();
|
|
if (assetPath.empty() || assetPath.find('\\') != std::string::npos ||
|
|
assetPath.find(':') != std::string::npos || assetPath.find('?') != std::string::npos ||
|
|
assetPath.find('#') != std::string::npos)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const std::filesystem::path path(assetPath);
|
|
if (path.empty() || path.is_absolute())
|
|
return false;
|
|
|
|
bool firstPart = true;
|
|
bool startsInUiDirectory = false;
|
|
for (const std::filesystem::path& part : path)
|
|
{
|
|
if (part.empty() || part == "." || part == "..")
|
|
return false;
|
|
if (firstPart)
|
|
{
|
|
startsInUiDirectory = part == "ui";
|
|
firstPart = false;
|
|
}
|
|
}
|
|
if (!startsInUiDirectory)
|
|
return false;
|
|
|
|
normalizedPath = path.lexically_normal();
|
|
if (normalizedPath.empty() || normalizedPath.is_absolute())
|
|
return false;
|
|
for (const std::filesystem::path& part : normalizedPath)
|
|
{
|
|
if (part.empty() || part == "." || part == "..")
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool IsModulePath(const std::filesystem::path& normalizedPath)
|
|
{
|
|
const std::string extension = normalizedPath.extension().string();
|
|
return extension == ".js" || extension == ".mjs";
|
|
}
|
|
|
|
bool ResolveAssetPath(
|
|
const std::filesystem::path& packageRoot,
|
|
const std::string& assetPath,
|
|
std::filesystem::path& resolvedPath)
|
|
{
|
|
resolvedPath.clear();
|
|
std::filesystem::path normalizedPath;
|
|
if (!NormalizeAssetPath(assetPath, normalizedPath))
|
|
return false;
|
|
|
|
const std::filesystem::path candidatePath = packageRoot / normalizedPath;
|
|
if (!IsPathUnderRoot(packageRoot, candidatePath))
|
|
return false;
|
|
if (!std::filesystem::exists(candidatePath) || !std::filesystem::is_regular_file(candidatePath))
|
|
return false;
|
|
|
|
resolvedPath = candidatePath;
|
|
return true;
|
|
}
|
|
}
|