2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-08 13:44:56 +00:00

Use UTF-8 exclusively internally

This removes SystemString, SystemChar, etc.
All filepaths and log strings are assumed to be UTF-8,
with conversions to UTF-16 for Windows APIs as appropriate.

Updates amuse, athena, boo, kabufua and nod
This commit is contained in:
2021-06-30 14:20:45 -04:00
parent 6e12554026
commit 9ca1a38171
160 changed files with 2029 additions and 2753 deletions

View File

@@ -1,8 +1,13 @@
set(BLENDER_SOURCES
Connection.cpp
MeshOptimizer.hpp
MeshOptimizer.cpp
SDNARead.cpp
HMDL.cpp)
Connection.cpp
MeshOptimizer.hpp
MeshOptimizer.cpp
SDNARead.cpp
HMDL.cpp)
hecl_add_list(Blender BLENDER_SOURCES)
set(FIND_BLENDER_SOURCES
FindBlender.cpp)
hecl_add_list(Blender FIND_BLENDER_SOURCES)

View File

@@ -14,6 +14,7 @@
#include <tuple>
#include "hecl/Blender/Connection.hpp"
#include "hecl/Blender/FindBlender.hpp"
#include "hecl/Blender/Token.hpp"
#include "hecl/Database.hpp"
#include "hecl/hecl.hpp"
@@ -48,20 +49,9 @@ using namespace std::literals;
namespace hecl::blender {
static const uint32_t MinBlenderMajorSearch = 2;
static const uint32_t MaxBlenderMajorSearch = 2;
static const uint32_t MinBlenderMinorSearch = 83;
static const uint32_t MaxBlenderMinorSearch = 92;
logvisor::Module BlenderLog("hecl::blender::Connection");
Token SharedBlenderToken;
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
extern "C" uint8_t HECL_BLENDERSHELL[];
extern "C" size_t HECL_BLENDERSHELL_SZ;
@@ -71,21 +61,21 @@ extern "C" size_t HECL_ADDON_SZ;
extern "C" uint8_t HECL_STARTUP[];
extern "C" size_t HECL_STARTUP_SZ;
static void InstallBlendershell(const SystemChar* path) {
auto fp = hecl::FopenUnique(path, _SYS_STR("w"));
static void InstallBlendershell(const char* path) {
auto fp = hecl::FopenUnique(path, "w");
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to open {} for writing")), path);
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to open {} for writing"), path);
}
std::fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp.get());
}
static void InstallAddon(const SystemChar* path) {
auto fp = hecl::FopenUnique(path, _SYS_STR("wb"));
static void InstallAddon(const char* path) {
auto fp = hecl::FopenUnique(path, "wb");
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to install blender addon at '{}'")), path);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to install blender addon at '{}'"), path);
}
std::fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp.get());
@@ -239,9 +229,8 @@ std::size_t Connection::_writeBuf(const void* buf, std::size_t len) {
ProjectPath Connection::_readPath() {
std::string path = _readStdString();
if (!path.empty()) {
SystemStringConv pathAbs(path);
SystemString meshPathRel =
getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(pathAbs.sys_str());
std::string meshPathRel =
getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(path);
return ProjectPath(getBlendPath().getProject().getProjectWorkingPath(), meshPathRel);
}
return {};
@@ -261,7 +250,7 @@ void Connection::_closePipe() {
void Connection::_blenderDied() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto errFp = hecl::FopenUnique(m_errPath.c_str(), _SYS_STR("r"));
auto errFp = hecl::FopenUnique(m_errPath.c_str(), "r");
if (errFp != nullptr) {
std::fseek(errFp.get(), 0, SEEK_END);
@@ -281,7 +270,7 @@ void Connection::_blenderDied() {
static std::atomic_bool BlenderFirstInit(false);
#if _WIN32
static bool RegFileExists(const hecl::SystemChar* path) {
static bool RegFileExists(const char* path) {
if (!path)
return false;
hecl::Sstat theStat;
@@ -295,16 +284,16 @@ Connection::Connection(int verbosityLevel) {
BlenderLog.report(logvisor::Info, FMT_STRING("Establishing BlenderConnection..."));
/* Put hecl_blendershell.py in temp dir */
const SystemChar* TMPDIR = GetTmpDir();
const std::string TMPDIR = GetTmpDir();
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
hecl::SystemString blenderShellPath(TMPDIR);
blenderShellPath += _SYS_STR("/hecl_blendershell.py");
std::string blenderShellPath(TMPDIR);
blenderShellPath += "/hecl_blendershell.py";
hecl::SystemString blenderAddonPath(TMPDIR);
blenderAddonPath += _SYS_STR("/hecl_blenderaddon.zip");
std::string blenderAddonPath(TMPDIR);
blenderAddonPath += "/hecl_blenderaddon.zip";
bool FalseCmp = false;
if (BlenderFirstInit.compare_exchange_strong(FalseCmp, true)) {
@@ -345,54 +334,16 @@ Connection::Connection(int verbosityLevel) {
pipe(m_writepipe.data());
#endif
/* User-specified blender path */
#if _WIN32
wchar_t BLENDER_BIN_BUF[2048];
std::wstring blenderBinBuf;
const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
#else
const char* blenderBin = getenv("BLENDER_BIN");
#endif
/* Steam blender */
hecl::SystemString steamBlender;
/* Child process of blender */
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin)) {
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp(_SYS_STR("Blender"));
if (steamBlender.size()) {
steamBlender += _SYS_STR("\\blender.exe");
blenderBin = steamBlender.c_str();
}
if (!RegFileExists(blenderBin)) {
/* No steam; try default */
wchar_t progFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256)) {
for (size_t major = MaxBlenderMajorSearch; major >= MinBlenderMajorSearch; --major) {
bool found = false;
for (size_t minor = MaxBlenderMinorSearch; minor >= MinBlenderMinorSearch; --minor) {
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender %i.%i\\blender.exe", progFiles, major,
minor);
if (RegFileExists(BLENDER_BIN_BUF)) {
blenderBin = BLENDER_BIN_BUF;
found = true;
break;
}
}
if (found) {
break;
}
}
}
}
int blenderMajor = 0;
int blenderMinor = 0;
auto blenderBin = blender::FindBlender(blenderMajor, blenderMinor);
if (!blenderBin) {
BlenderLog.report(logvisor::Fatal, FMT_STRING("Failed to locate Blender installation"));
}
std::wstring cmdLine = fmt::format(FMT_STRING(L" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
#if _WIN32
std::string cmdLine = fmt::format(FMT_STRING(" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING,
@@ -407,14 +358,16 @@ Connection::Connection(int verbosityLevel) {
sinfo.hStdOutput = consoleOutWrite;
}
if (!CreateProcessW(blenderBin, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
&sinfo, &m_pinfo)) {
const nowide::wstackstring wblenderBin(blenderBin.value());
nowide::wstackstring wcmdLine(cmdLine);
if (!CreateProcessW(wblenderBin.get(), wcmdLine.get(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr,
nullptr, &sinfo, &m_pinfo)) {
LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
nullptr);
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to launch blender from {}: {}"), blenderBin,
messageBuffer);
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to launch blender from {}: {}"), blenderBin.value(),
nowide::narrow(messageBuffer));
}
close(m_writepipe[0]);
@@ -475,8 +428,8 @@ Connection::Connection(int verbosityLevel) {
/* Try user-specified blender first */
if (blenderBin) {
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
execlp(blenderBin->c_str(), blenderBin->c_str(), "--background", "-P", blenderShellPath.c_str(), "--",
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) {
errbuf = fmt::format(FMT_STRING("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@@ -485,16 +438,15 @@ Connection::Connection(int verbosityLevel) {
}
/* Try steam */
steamBlender = hecl::FindCommonSteamApp(_SYS_STR("Blender"));
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
#ifdef __APPLE__
steamBlender += "/blender.app/Contents/MacOS/blender";
#else
steamBlender += "/blender";
#endif
blenderBin = steamBlender.c_str();
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
execlp(steamBlender.c_str(), steamBlender.c_str(), "--background", "-P", blenderShellPath.c_str(), "--",
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) {
errbuf = fmt::format(FMT_STRING("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@@ -522,11 +474,11 @@ Connection::Connection(int verbosityLevel) {
/* Stash error path and unlink existing file */
#if _WIN32
m_errPath = hecl::SystemString(TMPDIR) +
fmt::format(FMT_STRING(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_pinfo.dwProcessId);
m_errPath = std::string(TMPDIR) +
fmt::format(FMT_STRING("/hecl_{:016X}.derp"), (unsigned long long)m_pinfo.dwProcessId);
#else
m_errPath = hecl::SystemString(TMPDIR) +
fmt::format(FMT_STRING(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc);
m_errPath = std::string(TMPDIR) +
fmt::format(FMT_STRING("/hecl_{:016X}.derp"), (unsigned long long)m_blenderProc);
#endif
hecl::Unlink(m_errPath.c_str());
@@ -539,25 +491,25 @@ Connection::Connection(int verbosityLevel) {
} else if (!lineStr.compare(0, 9, "NOBLENDER")) {
_closePipe();
#if _WIN32
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}'")), blenderBin);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}'"), blenderBin.value());
#else
if (blenderBin)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}' or '{}'")), blenderBin,
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}' or '{}'"), blenderBin,
DEFAULT_BLENDER_BIN);
else
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}'")), DEFAULT_BLENDER_BIN);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}'"), DEFAULT_BLENDER_BIN);
#endif
} else if (lineStr == "INVALIDBLENDERVER") {
_closePipe();
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Installed blender version must be >= {}.{}")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("Installed blender version must be >= {}.{}"),
MinBlenderMajorSearch, MinBlenderMinorSearch);
} else if (lineStr == "NOADDON") {
_closePipe();
if (blenderAddonPath != _SYS_STR("SKIPINSTALL"))
if (blenderAddonPath != "SKIPINSTALL")
InstallAddon(blenderAddonPath.c_str());
++installAttempt;
if (installAttempt >= 2)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to install blender addon using '{}'")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to install blender addon using '{}'"),
blenderAddonPath.c_str());
#ifndef _WIN32
waitpid(pid, nullptr, 0);
@@ -565,7 +517,7 @@ Connection::Connection(int verbosityLevel) {
continue;
} else if (lineStr == "ADDONINSTALLED") {
_closePipe();
blenderAddonPath = _SYS_STR("SKIPINSTALL");
blenderAddonPath = "SKIPINSTALL";
#ifndef _WIN32
waitpid(pid, nullptr, 0);
#endif
@@ -654,7 +606,7 @@ bool Connection::createBlend(const ProjectPath& path, BlendType type) {
FMT_STRING("BlenderConnection::createBlend() musn't be called with stream active"));
return false;
}
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePathUTF8(), BlendTypeStrs[int(type)]));
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePath(), BlendTypeStrs[int(type)]));
if (_isFinished()) {
/* Delete immediately in case save doesn't occur */
hecl::Unlink(path.getAbsolutePath().data());
@@ -673,7 +625,7 @@ bool Connection::openBlend(const ProjectPath& path, bool force) {
}
if (!force && path == m_loadedBlend)
return true;
_writeStr(fmt::format(FMT_STRING("OPEN \"{}\""), path.getAbsolutePathUTF8()));
_writeStr(fmt::format(FMT_STRING("OPEN \"{}\""), path.getAbsolutePath()));
if (_isFinished()) {
m_loadedBlend = path;
_writeStr("GETTYPE");
@@ -711,7 +663,7 @@ bool Connection::saveBlend() {
void Connection::deleteBlend() {
if (m_loadedBlend) {
hecl::Unlink(m_loadedBlend.getAbsolutePath().data());
BlenderLog.report(logvisor::Info, FMT_STRING(_SYS_STR("Deleted '{}'")), m_loadedBlend.getAbsolutePath());
BlenderLog.report(logvisor::Info, FMT_STRING("Deleted '{}'"), m_loadedBlend.getAbsolutePath());
m_loadedBlend = ProjectPath();
}
}
@@ -1203,8 +1155,7 @@ MapUniverse::World::World(Connection& conn) {
color.read(conn);
std::string path = conn._readStdString();
if (!path.empty()) {
hecl::SystemStringConv sysPath(path);
worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), sysPath.sys_str());
worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), path);
}
}
@@ -1350,7 +1301,7 @@ std::vector<std::string> DataStream::getLightList() {
std::pair<atVec3f, atVec3f> DataStream::getMeshAABB() {
if (m_parent->m_loadedType != BlendType::Mesh && m_parent->m_loadedType != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MESH or ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MESH or ACTOR blend"),
m_parent->m_loadedBlend.getAbsolutePath());
m_parent->_writeStr("MESHAABB");
@@ -1368,7 +1319,7 @@ const char* DataStream::MeshOutputModeString(HMDLTopology topology) {
Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount) {
if (m_parent->getBlendType() != BlendType::Mesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MESH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MESH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILE");
@@ -1379,7 +1330,7 @@ Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount) {
Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount, bool useLuv) {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("MESHCOMPILENAME {} {}"), name, int(useLuv)));
@@ -1390,7 +1341,7 @@ Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, int s
ColMesh DataStream::compileColMesh(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("MESHCOMPILENAMECOLLISION {}"), name));
@@ -1401,7 +1352,7 @@ ColMesh DataStream::compileColMesh(std::string_view name) {
std::vector<ColMesh> DataStream::compileColMeshes() {
if (m_parent->getBlendType() != BlendType::ColMesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a CMESH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a CMESH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILECOLLISIONALL");
@@ -1414,7 +1365,7 @@ std::vector<ColMesh> DataStream::compileColMeshes() {
std::vector<Light> DataStream::compileLights() {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("LIGHTCOMPILEALL");
@@ -1427,7 +1378,7 @@ std::vector<Light> DataStream::compileLights() {
PathMesh DataStream::compilePathMesh() {
if (m_parent->getBlendType() != BlendType::PathMesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a PATH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a PATH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILEPATH");
@@ -1438,7 +1389,7 @@ PathMesh DataStream::compilePathMesh() {
std::vector<uint8_t> DataStream::compileGuiFrame(int version) {
if (m_parent->getBlendType() != BlendType::Frame)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a FRAME blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a FRAME blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("FRAMECOMPILE {}"), version));
@@ -1449,13 +1400,12 @@ std::vector<uint8_t> DataStream::compileGuiFrame(int version) {
if (readStr == "FRAMEDONE")
break;
SystemStringConv absolute(readStr);
auto& proj = m_parent->getBlendPath().getProject();
SystemString relative;
if (PathRelative(absolute.c_str()))
relative = absolute.sys_str();
std::string relative;
if (PathRelative(readStr.c_str()))
relative = readStr;
else
relative = proj.getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str());
relative = proj.getProjectRootPath().getProjectRelativeFromAbsolute(readStr);
hecl::ProjectPath path(proj.getProjectWorkingPath(), relative);
m_parent->_writeStr(fmt::format(FMT_STRING("{:08X}"), path.parsedHash32()));
@@ -1478,7 +1428,7 @@ std::vector<ProjectPath> DataStream::getTextures() {
Actor DataStream::compileActor() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ACTORCOMPILE");
@@ -1489,7 +1439,7 @@ Actor DataStream::compileActor() {
Actor DataStream::compileActorCharacterOnly() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ACTORCOMPILECHARACTERONLY");
@@ -1500,7 +1450,7 @@ Actor DataStream::compileActorCharacterOnly() {
Armature DataStream::compileArmature() {
if (m_parent->getBlendType() != BlendType::Armature)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ARMATURE blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ARMATURE blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ARMATURECOMPILE");
@@ -1511,7 +1461,7 @@ Armature DataStream::compileArmature() {
Action DataStream::compileActionChannelsOnly(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("ACTIONCOMPILECHANNELSONLY {}"), name));
@@ -1522,7 +1472,7 @@ Action DataStream::compileActionChannelsOnly(std::string_view name) {
World DataStream::compileWorld() {
if (m_parent->getBlendType() != BlendType::World)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an WORLD blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an WORLD blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("WORLDCOMPILE");
@@ -1533,7 +1483,7 @@ World DataStream::compileWorld() {
std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETSUBTYPENAMES");
@@ -1551,7 +1501,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeNames() {
std::vector<std::pair<std::string, std::string>> DataStream::getActionNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETACTIONNAMES");
@@ -1569,7 +1519,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getActionNames() {
std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeOverlayNames(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("GETSUBTYPEOVERLAYNAMES {}"), name));
@@ -1587,7 +1537,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeOverlayNa
std::vector<std::pair<std::string, std::string>> DataStream::getAttachmentNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETATTACHMENTNAMES");
@@ -1608,7 +1558,7 @@ std::unordered_map<std::string, Matrix3f> DataStream::getBoneMatrices(std::strin
return {};
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("GETBONEMATRICES {}"), name));
@@ -1643,7 +1593,7 @@ bool DataStream::renderPvs(std::string_view path, const atVec3f& location) {
return false;
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
athena::simd_floats f(location.simd);
@@ -1658,7 +1608,7 @@ bool DataStream::renderPvsLight(std::string_view path, std::string_view lightNam
return false;
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("RENDERPVSLIGHT {} {}"), path, lightName));
@@ -1669,7 +1619,7 @@ bool DataStream::renderPvsLight(std::string_view path, std::string_view lightNam
MapArea DataStream::compileMapArea() {
if (m_parent->getBlendType() != BlendType::MapArea)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MAPAREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MAPAREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MAPAREACOMPILE");
@@ -1680,7 +1630,7 @@ MapArea DataStream::compileMapArea() {
MapUniverse DataStream::compileMapUniverse() {
if (m_parent->getBlendType() != BlendType::MapUniverse)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MAPUNIVERSE blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MAPUNIVERSE blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MAPUNIVERSECOMPILE");

View File

@@ -0,0 +1,144 @@
#include "hecl/Blender/FindBlender.hpp"
#include "hecl/SteamFinder.hpp"
#include "hecl/hecl.hpp"
namespace hecl::blender {
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
static const std::regex regBlenderVersion(R"(Blender (\d+)\.(\d+)(?:\.(\d+))?)",
std::regex::ECMAScript | std::regex::optimize);
static bool RegFileExists(const char* path) {
if (!path)
return false;
hecl::Sstat theStat;
return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode);
}
std::optional<std::string> FindBlender(int& major, int& minor) {
major = 0;
minor = 0;
/* User-specified blender path */
#if _WIN32
auto blenderBin = GetEnv("BLENDER_BIN");
#else
const char* cblenderBin = getenv("BLENDER_BIN");
std::optional<std::string> blenderBin{};
if (cblenderBin != nullptr) {
blenderBin = cblenderBin;
}
#endif
/* Steam blender */
std::string steamBlender;
/* Child process of blender */
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin->c_str())) {
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
steamBlender += "\\blender.exe";
blenderBin = steamBlender.c_str();
}
if (!RegFileExists(blenderBin->c_str())) {
/* No steam; try default */
wchar_t wProgFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", wProgFiles, 256)) {
auto progFiles = nowide::narrow(wProgFiles);
for (size_t major = MaxBlenderMajorSearch; major >= MinBlenderMajorSearch; --major) {
bool found = false;
for (size_t minor = MaxBlenderMinorSearch; minor >= MinBlenderMinorSearch; --minor) {
std::string blenderBinBuf = fmt::format(FMT_STRING("{}\\Blender Foundation\\Blender {}.{}\\blender.exe"),
progFiles, major, minor);
if (RegFileExists(blenderBinBuf.c_str())) {
blenderBin = std::move(blenderBinBuf);
found = true;
break;
}
}
if (found) {
break;
}
}
}
}
}
#else
if (!RegFileExists(blenderBin)) {
/* Try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
#ifdef __APPLE__
steamBlender += "/blender.app/Contents/MacOS/blender";
#else
steamBlender += "/blender";
#endif
blenderBin = steamBlender.c_str();
if (!RegFileExists(blenderBin)) {
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin)) {
blenderBin = nullptr;
}
}
} else {
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin)) {
blenderBin = nullptr;
}
}
}
#endif
if (!blenderBin)
return {};
#if _WIN32
const nowide::wstackstring wblenderBin(blenderBin.value());
DWORD handle = 0;
DWORD infoSize = GetFileVersionInfoSizeW(wblenderBin.get(), &handle);
if (infoSize != NULL) {
auto* infoData = new char[infoSize];
if (GetFileVersionInfoW(wblenderBin.get(), handle, infoSize, infoData)) {
UINT size = 0;
LPVOID lpBuffer = nullptr;
if (VerQueryValueW(infoData, L"\\", &lpBuffer, &size) && size != 0u) {
auto* verInfo = static_cast<VS_FIXEDFILEINFO*>(lpBuffer);
if (verInfo->dwSignature == 0xfeef04bd) {
major = static_cast<int>((verInfo->dwFileVersionMS >> 16) & 0xffff);
minor = static_cast<int>((verInfo->dwFileVersionMS >> 0 & 0xffff) * 10 +
(verInfo->dwFileVersionLS >> 16 & 0xffff));
}
}
}
delete[] infoData;
}
#else
std::string command = std::string("\"") + blenderBin + "\" --version";
FILE* fp = popen(command.c_str(), "r");
char versionBuf[256];
size_t rdSize = fread(versionBuf, 1, 255, fp);
versionBuf[rdSize] = '\0';
pclose(fp);
std::cmatch match;
if (std::regex_search(versionBuf, match, regBlenderVersion)) {
major = atoi(match[1].str().c_str());
minor = atoi(match[2].str().c_str());
}
#endif
return blenderBin;
}
} // namespace hecl::blender

View File

@@ -69,7 +69,7 @@ void SDNARead::enumerate(const std::function<bool(const FileBlock& block, athena
}
}
SDNARead::SDNARead(SystemStringView path) {
SDNARead::SDNARead(std::string_view path) {
athena::io::FileReader r(path);
if (r.hasError())
return;
@@ -134,7 +134,7 @@ SDNARead::SDNARead(SystemStringView path) {
});
}
BlendType GetBlendType(SystemStringView path) {
BlendType GetBlendType(std::string_view path) {
SDNARead r(path);
if (!r)
return BlendType::None;

View File

@@ -35,7 +35,6 @@ set(HECL_HEADERS
../include/hecl/Database.hpp
../include/hecl/Runtime.hpp
../include/hecl/ClientProcess.hpp
../include/hecl/SystemChar.hpp
../include/hecl/BitVector.hpp
../include/hecl/MathExtras.hpp
../include/hecl/UniformBufferPool.hpp
@@ -63,27 +62,32 @@ if(UNIX)
endif()
add_library(hecl-full
${FRONTEND_SOURCES}
${RUNTIME_SOURCES}
${BLENDER_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
Pipeline.cpp)
${FRONTEND_SOURCES}
${RUNTIME_SOURCES}
${BLENDER_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
Pipeline.cpp)
target_include_directories(hecl-full PUBLIC ../include)
target_link_libraries(hecl-full PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST}
hecl-blender-addon boo athena-core logvisor)
hecl-blender-addon boo athena-core logvisor)
target_atdna(hecl-full atdna_HMDLMeta_full.cpp ../include/hecl/HMDLMeta.hpp)
target_atdna(hecl-full atdna_CVar_full.cpp ../include/hecl/CVar.hpp)
target_atdna(hecl-full atdna_SDNARead_full.cpp ../include/hecl/Blender/SDNARead.hpp)
add_library(hecl-light
${RUNTIME_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS})
${RUNTIME_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
${FIND_BLENDER_SOURCES})
target_include_directories(hecl-light PUBLIC ../include)
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor)
if (WIN32)
# For FindBlender
target_link_libraries(hecl-light PUBLIC Version)
endif ()
target_atdna(hecl-light atdna_HMDLMeta_light.cpp ../include/hecl/HMDLMeta.hpp)
target_atdna(hecl-light atdna_CVar_light.cpp ../include/hecl/CVar.hpp)

View File

@@ -259,18 +259,6 @@ std::string CVar::toLiteral(bool* isValid) const {
return m_value;
}
std::wstring CVar::toWideLiteral(bool* isValid) const {
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (isValid != nullptr)
*isValid = false;
} else if (isValid != nullptr) {
*isValid = true;
}
// Even if it's not a literal, it's still safe to return
return hecl::UTF8ToWide(m_value);
}
bool CVar::fromVec2f(const atVec2f& val) {
if (!safeToModify(EType::Vec2f))
return false;
@@ -398,15 +386,6 @@ bool CVar::fromLiteral(std::string_view val) {
return true;
}
bool CVar::fromLiteral(std::wstring_view val) {
if (!safeToModify(EType::Literal))
return false;
m_value.assign(hecl::WideToUTF8(val));
setModified();
return true;
}
bool CVar::fromLiteralToType(std::string_view val) {
if (!safeToModify(m_type) || !isValidInput(val))
return false;
@@ -415,8 +394,6 @@ bool CVar::fromLiteralToType(std::string_view val) {
return true;
}
bool CVar::fromLiteralToType(std::wstring_view val) { return fromLiteralToType(hecl::WideToUTF8(val)); }
bool CVar::isModified() const { return True(m_flags & EFlags::Modified); }
bool CVar::modificationRequiresRestart() const { return True(m_flags & EFlags::ModifyRestart); }
@@ -523,8 +500,6 @@ bool CVar::isValidInput(std::string_view input) const {
return false;
}
bool CVar::isValidInput(std::wstring_view input) const { return isValidInput(hecl::WideToUTF8(input)); }
bool CVar::safeToModify(EType type) const {
// Are we NoDevelper?
if (isNoDeveloper())

View File

@@ -111,18 +111,13 @@ void CVarManager::deserialize(CVar* cvar) {
}
/* We were either unable to find a deferred value or got an invalid value */
#if _WIN32
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
std::string filename =
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
hecl::Sstat st;
if (m_useBinary) {
CVarContainer container;
filename += _SYS_STR(".bin");
filename += ".bin";
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
athena::io::FileReader reader(filename);
@@ -144,7 +139,7 @@ void CVarManager::deserialize(CVar* cvar) {
}
}
} else {
filename += _SYS_STR(".yaml");
filename += ".yaml";
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
athena::io::FileReader reader(filename);
@@ -170,13 +165,8 @@ void CVarManager::deserialize(CVar* cvar) {
}
void CVarManager::serialize() {
#if _WIN32
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
std::string filename =
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
if (m_useBinary) {
CVarContainer container;
@@ -189,12 +179,12 @@ void CVarManager::serialize() {
}
container.cvarCount = atUint32(container.cvars.size());
filename += _SYS_STR(".bin");
filename += ".bin";
athena::io::FileWriter writer(filename);
if (writer.isOpen())
container.write(writer);
} else {
filename += _SYS_STR(".yaml");
filename += ".yaml";
athena::io::FileReader r(filename);
athena::io::YAMLDocWriter docWriter(r.isOpen() ? &r : nullptr);
@@ -297,21 +287,20 @@ bool CVarManager::restartRequired() const {
});
}
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
void CVarManager::parseCommandLine(const std::vector<std::string>& args) {
bool oldDeveloper = suppressDeveloper();
std::string developerName(com_developer->name());
athena::utility::tolower(developerName);
for (const SystemString& arg : args) {
if (arg[0] != _SYS_STR('+')) {
for (const std::string& arg : args) {
if (arg[0] != '+') {
continue;
}
const std::string tmp(SystemUTF8Conv(arg).str());
std::smatch matches;
std::string cvarName;
std::string cvarValue;
if (std::regex_match(tmp, matches, cmdLineRegex)) {
if (std::regex_match(arg, matches, cmdLineRegex)) {
std::vector<std::string> realMatches;
for (auto match : matches) {
if (match.matched) {

View File

@@ -26,7 +26,7 @@ ThreadLocalPtr<ClientProcess::Worker> ClientProcess::ThreadWorker;
int CpuCountOverride = 0;
void SetCpuCountOverride(int argc, const SystemChar** argv) {
void SetCpuCountOverride(int argc, char** argv) {
bool threadArg = false;
for (int i = 1; i < argc; ++i) {
if (threadArg) {
@@ -35,7 +35,7 @@ void SetCpuCountOverride(int argc, const SystemChar** argv) {
return;
}
}
if (!hecl::StrNCmp(argv[i], _SYS_STR("-j"), 2)) {
if (!hecl::StrNCmp(argv[i], "-j", 2)) {
if (int count = int(hecl::StrToUl(argv[i] + 2, nullptr, 0))) {
CpuCountOverride = count;
return;
@@ -65,7 +65,7 @@ static int GetCPUCount() {
void ClientProcess::BufferTransaction::run(blender::Token& btok) {
athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false);
if (r.hasError()) {
CP_Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to background-buffer '{}'")), m_path.getAbsolutePath());
CP_Log.report(logvisor::Fatal, FMT_STRING("unable to background-buffer '{}'"), m_path.getAbsolutePath());
return;
}
if (m_offset)
@@ -175,30 +175,30 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
if (specEnt) {
hecl::ProjectPath cooked = path.getCookedPath(*specEnt);
if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast"));
cooked = cooked.getWithExtension(".fast");
cooked.makeDirChain(false);
if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
if (m_progPrinter) {
hecl::SystemString str;
std::string str;
if (path.getAuxInfo().empty())
str = fmt::format(FMT_STRING(_SYS_STR("Cooking {}")), path.getRelativePath());
str = fmt::format(FMT_STRING("Cooking {}"), path.getRelativePath());
else
str = fmt::format(FMT_STRING(_SYS_STR("Cooking {}|{}")), path.getRelativePath(), path.getAuxInfo());
str = fmt::format(FMT_STRING("Cooking {}|{}"), path.getRelativePath(), path.getAuxInfo());
m_progPrinter->print(str, std::nullopt, -1.f, hecl::ClientProcess::GetThreadWorkerIdx());
m_progPrinter->flush();
} else {
if (path.getAuxInfo().empty())
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Cooking {}")), path.getRelativePath());
LogModule.report(logvisor::Info, FMT_STRING("Cooking {}"), path.getRelativePath());
else
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Cooking {}|{}")), path.getRelativePath(), path.getAuxInfo());
LogModule.report(logvisor::Info, FMT_STRING("Cooking {}|{}"), path.getRelativePath(), path.getAuxInfo());
}
spec->doCook(path, cooked, false, btok, [](const SystemChar*) {});
spec->doCook(path, cooked, false, btok, [](const char*) {});
if (m_progPrinter) {
hecl::SystemString str;
std::string str;
if (path.getAuxInfo().empty())
str = fmt::format(FMT_STRING(_SYS_STR("Cooked {}")), path.getRelativePath());
str = fmt::format(FMT_STRING("Cooked {}"), path.getRelativePath());
else
str = fmt::format(FMT_STRING(_SYS_STR("Cooked {}|{}")), path.getRelativePath(), path.getAuxInfo());
str = fmt::format(FMT_STRING("Cooked {}|{}"), path.getRelativePath(), path.getAuxInfo());
m_progPrinter->print(str, std::nullopt, -1.f, hecl::ClientProcess::GetThreadWorkerIdx());
m_progPrinter->flush();
}

View File

@@ -378,16 +378,6 @@ void Console::LogVisorAdapter::report(const char* modName, logvisor::Level sever
}
}
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity,
fmt::wstring_view format, fmt::wformat_args args) {
auto tmp = fmt::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) {
auto v = fmt::format(FMT_STRING("[{}] {}"), modName, line);
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
}
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
unsigned linenum, fmt::string_view format, fmt::format_args args) {
auto tmp = fmt::vformat(format, args);
@@ -395,16 +385,6 @@ void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
unsigned linenum, fmt::wstring_view format, fmt::wformat_args args) {
auto tmp = fmt::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) {
auto v = fmt::format(FMT_STRING("[{}] {} {}:{}"), modName, line, file, linenum);
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
}
void Console::dumpLog() {
for (const auto& l : m_log) {
switch (l.second) {

View File

@@ -38,20 +38,20 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const {
if (submessageLen) {
if (messageLen > half - submessageLen - 1)
fmt::print(FMT_STRING(_SYS_STR(" {:.{}}... {} ")), m_message, half - submessageLen - 4, m_submessage);
fmt::print(FMT_STRING(" {:.{}}... {} "), m_message, half - submessageLen - 4, m_submessage);
else {
fmt::print(FMT_STRING(_SYS_STR(" {}")), m_message);
fmt::print(FMT_STRING(" {}"), m_message);
for (int i = half - messageLen - submessageLen - 1; i >= 0; --i)
fmt::print(FMT_STRING(_SYS_STR(" ")));
fmt::print(FMT_STRING(_SYS_STR("{} ")), m_submessage);
fmt::print(FMT_STRING(" "));
fmt::print(FMT_STRING("{} "), m_submessage);
}
} else {
if (messageLen > half)
fmt::print(FMT_STRING(_SYS_STR(" {:.{}}... ")), m_message, half - 3);
fmt::print(FMT_STRING(" {:.{}}... "), m_message, half - 3);
else {
fmt::print(FMT_STRING(_SYS_STR(" {}")), m_message);
fmt::print(FMT_STRING(" {}"), m_message);
for (int i = half - messageLen; i >= 0; --i)
fmt::print(FMT_STRING(_SYS_STR(" ")));
fmt::print(FMT_STRING(" "));
}
}
@@ -62,22 +62,22 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const {
int rem = nblocks - filled;
if (tinfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD "{:3d}% [")), iFactor);
fmt::print(FMT_STRING("" BOLD "{:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(tinfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR("{:3d}% [")), iFactor);
fmt::print(FMT_STRING("{:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(tinfo.console, FOREGROUND_WHITE);
#endif
@@ -100,24 +100,24 @@ void MultiProgressPrinter::DrawIndeterminateBar() {
int rem = blocks - pre - 1;
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD " [")));
fmt::print(FMT_STRING("" BOLD " ["));
for (int b = 0; b < pre; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR(" [")));
fmt::print(FMT_STRING(" ["));
for (int b = 0; b < pre; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_WHITE);
#endif
@@ -127,7 +127,7 @@ void MultiProgressPrinter::DrawIndeterminateBar() {
void MultiProgressPrinter::MoveCursorUp(int n) {
if (n) {
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" PREV_LINE "")), n);
fmt::print(FMT_STRING("" PREV_LINE ""), n);
}
#if _WIN32
else {
@@ -139,7 +139,7 @@ void MultiProgressPrinter::MoveCursorUp(int n) {
}
#endif
} else {
fmt::print(FMT_STRING(_SYS_STR("\r")));
fmt::print(FMT_STRING("\r"));
}
}
@@ -157,7 +157,7 @@ void MultiProgressPrinter::DoPrint() {
SetConsoleCursorInfo(m_termInfo.console, &cursorInfo);
#endif
if (m_termInfo.xtermColor)
fmt::print(FMT_STRING(_SYS_STR("" HIDE_CURSOR "")));
fmt::print(FMT_STRING("" HIDE_CURSOR ""));
if (m_dirty) {
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth(&m_termInfo.truncate)));
@@ -168,7 +168,7 @@ void MultiProgressPrinter::DoPrint() {
for (const ThreadStat& stat : m_threadStats) {
if (stat.m_active) {
stat.print(m_termInfo);
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curThreadLines;
}
}
@@ -179,7 +179,7 @@ void MultiProgressPrinter::DoPrint() {
#endif
) {
DrawIndeterminateBar();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
} else if (m_mainFactor >= 0.f) {
float factor = std::max(0.0f, std::min(1.0f, m_mainFactor));
@@ -191,34 +191,34 @@ void MultiProgressPrinter::DoPrint() {
int rem = blocks - filled;
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD " {:3d}% [")), iFactor);
fmt::print(FMT_STRING("" BOLD " {:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR(" {:3d}% [")), iFactor);
fmt::print(FMT_STRING(" {:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_WHITE);
#endif
}
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
}
} else if (m_latestThread != -1) {
const ThreadStat& stat = m_threadStats[m_latestThread];
stat.print(m_termInfo);
fmt::print(FMT_STRING(_SYS_STR("\r")));
fmt::print(FMT_STRING("\r"));
}
m_dirty = false;
} else if (m_mainIndeterminate
@@ -230,12 +230,12 @@ void MultiProgressPrinter::DoPrint() {
MoveCursorUp(m_curProgLines);
m_curProgLines = 0;
DrawIndeterminateBar();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
}
if (m_termInfo.xtermColor)
fmt::print(FMT_STRING(_SYS_STR("" SHOW_CURSOR "")));
fmt::print(FMT_STRING("" SHOW_CURSOR ""));
fflush(stdout);
#if _WIN32
@@ -286,8 +286,8 @@ MultiProgressPrinter::~MultiProgressPrinter() {
m_logThread.join();
}
void MultiProgressPrinter::print(std::optional<hecl::SystemStringView> message,
std::optional<hecl::SystemStringView> submessage,
void MultiProgressPrinter::print(std::optional<std::string_view> message,
std::optional<std::string_view> submessage,
float factor,
int threadIdx) const {
if (!m_running) {
@@ -356,7 +356,7 @@ void MultiProgressPrinter::startNewLine() const {
m_curThreadLines = 0;
m_mainFactor = -1.f;
auto logLk = logvisor::LockLog();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
}
void MultiProgressPrinter::flush() const {

View File

@@ -15,7 +15,7 @@ class ShaderCacheZipStream : public athena::io::IStreamReader {
z_stream m_zstrm = {};
public:
explicit ShaderCacheZipStream(const hecl::SystemChar* path) : m_reader(path) {
explicit ShaderCacheZipStream(const char* path) : m_reader(path) {
if (m_reader.hasError())
return;
if (m_reader.readUint32Big() != SBIG('SHAD'))
@@ -91,7 +91,7 @@ static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZip
}
template <typename P>
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path) {
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const char* path) {
ShaderCacheZipStream r(path);
if (!r)
return false;

View File

@@ -43,8 +43,8 @@ static bool CheckNewLineAdvance(std::string::const_iterator& it) {
return false;
}
Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir) {
m_filepath = SystemString(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data();
Project::ConfigFile::ConfigFile(const Project& project, std::string_view name, std::string_view subdir) {
m_filepath = std::string(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data();
}
std::vector<std::string>& Project::ConfigFile::lockAndRead() {
@@ -52,7 +52,7 @@ std::vector<std::string>& Project::ConfigFile::lockAndRead() {
return m_lines;
}
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), "a+", FileLockType::Write);
hecl::FSeek(m_lockedFile.get(), 0, SEEK_SET);
std::string mainString;
@@ -132,8 +132,8 @@ bool Project::ConfigFile::unlockAndCommit() {
return false;
}
const SystemString newPath = m_filepath + _SYS_STR(".part");
auto newFile = hecl::FopenUnique(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
const std::string newPath = m_filepath + ".part";
auto newFile = hecl::FopenUnique(newPath.c_str(), "w", FileLockType::Write);
bool fail = false;
for (const std::string& line : m_lines) {
if (std::fwrite(line.c_str(), 1, line.size(), newFile.get()) != line.size()) {
@@ -149,19 +149,10 @@ bool Project::ConfigFile::unlockAndCommit() {
newFile.reset();
m_lockedFile.reset();
if (fail) {
#if HECL_UCS2
_wunlink(newPath.c_str());
#else
unlink(newPath.c_str());
#endif
Unlink(newPath.c_str());
return false;
} else {
#if HECL_UCS2
//_wrename(newPath.c_str(), m_filepath.c_str());
MoveFileExW(newPath.c_str(), m_filepath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
#else
rename(newPath.c_str(), m_filepath.c_str());
#endif
Rename(newPath.c_str(), m_filepath.c_str());
return true;
}
}
@@ -172,21 +163,21 @@ bool Project::ConfigFile::unlockAndCommit() {
Project::Project(const ProjectRootPath& rootPath)
: m_rootPath(rootPath)
, m_workRoot(*this, _SYS_STR(""))
, m_dotPath(m_workRoot, _SYS_STR(".hecl"))
, m_cookedRoot(m_dotPath, _SYS_STR("cooked"))
, m_specs(*this, _SYS_STR("specs"))
, m_paths(*this, _SYS_STR("paths"))
, m_groups(*this, _SYS_STR("groups")) {
, m_workRoot(*this, "")
, m_dotPath(m_workRoot, ".hecl")
, m_cookedRoot(m_dotPath, "cooked")
, m_specs(*this, "specs")
, m_paths(*this, "paths")
, m_groups(*this, "groups") {
/* Stat for existing project directory (must already exist) */
Sstat myStat;
if (hecl::Stat(m_rootPath.getAbsolutePath().data(), &myStat)) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), m_rootPath.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), m_rootPath.getAbsolutePath());
return;
}
if (!S_ISDIR(myStat.st_mode)) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("provided path must be a directory; '{}' isn't")),
LogModule.report(logvisor::Error, FMT_STRING("provided path must be a directory; '{}' isn't"),
m_rootPath.getAbsolutePath());
return;
}
@@ -196,8 +187,8 @@ Project::Project(const ProjectRootPath& rootPath)
m_cookedRoot.makeDir();
/* Ensure beacon is valid or created */
const ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
const ProjectPath beaconPath(m_dotPath, "beacon");
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), "a+b");
struct BeaconStruct {
hecl::FourCC magic;
uint32_t version;
@@ -225,14 +216,14 @@ const ProjectPath& Project::getProjectCookedPath(const DataSpecEntry& spec) cons
for (const ProjectDataSpec& sp : m_compiledSpecs)
if (&sp.spec == &spec)
return sp.cookedPath;
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find spec '{}'")), spec.m_name);
LogModule.report(logvisor::Fatal, FMT_STRING("Unable to find spec '{}'"), spec.m_name);
return m_cookedRoot;
}
bool Project::addPaths(const std::vector<ProjectPath>& paths) {
m_paths.lockAndRead();
for (const ProjectPath& path : paths)
m_paths.addLine(path.getRelativePathUTF8());
m_paths.addLine(path.getRelativePath());
return m_paths.unlockAndCommit();
}
@@ -240,7 +231,7 @@ bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive)
std::vector<std::string>& existingPaths = m_paths.lockAndRead();
if (recursive) {
for (const ProjectPath& path : paths) {
auto recursiveBase = path.getRelativePathUTF8();
auto recursiveBase = path.getRelativePath();
for (auto it = existingPaths.begin(); it != existingPaths.end();) {
if (!(*it).compare(0, recursiveBase.size(), recursiveBase)) {
it = existingPaths.erase(it);
@@ -251,19 +242,19 @@ bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive)
}
} else
for (const ProjectPath& path : paths)
m_paths.removeLine(path.getRelativePathUTF8());
m_paths.removeLine(path.getRelativePath());
return m_paths.unlockAndCommit();
}
bool Project::addGroup(const hecl::ProjectPath& path) {
m_groups.lockAndRead();
m_groups.addLine(path.getRelativePathUTF8());
m_groups.addLine(path.getRelativePath());
return m_groups.unlockAndCommit();
}
bool Project::removeGroup(const ProjectPath& path) {
m_groups.lockAndRead();
m_groups.removeLine(path.getRelativePathUTF8());
m_groups.removeLine(path.getRelativePath());
return m_groups.unlockAndCommit();
}
@@ -271,30 +262,26 @@ void Project::rescanDataSpecs() {
m_compiledSpecs.clear();
m_specs.lockAndRead();
for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY) {
hecl::SystemString specStr(spec->m_name);
SystemUTF8Conv specUTF8(specStr);
m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, hecl::SystemString(spec->m_name) + _SYS_STR(".spec")),
m_specs.checkForLine(specUTF8.str())});
m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, std::string(spec->m_name) + ".spec"),
m_specs.checkForLine(spec->m_name)});
}
m_specs.unlockAndDiscard();
}
bool Project::enableDataSpecs(const std::vector<SystemString>& specs) {
bool Project::enableDataSpecs(const std::vector<std::string>& specs) {
m_specs.lockAndRead();
for (const SystemString& spec : specs) {
SystemUTF8Conv specView(spec);
m_specs.addLine(specView.str());
for (const std::string& spec : specs) {
m_specs.addLine(spec);
}
bool result = m_specs.unlockAndCommit();
rescanDataSpecs();
return result;
}
bool Project::disableDataSpecs(const std::vector<SystemString>& specs) {
bool Project::disableDataSpecs(const std::vector<std::string>& specs) {
m_specs.lockAndRead();
for (const SystemString& spec : specs) {
SystemUTF8Conv specView(spec);
m_specs.removeLine(specView.str());
for (const std::string& spec : specs) {
m_specs.removeLine(spec);
}
bool result = m_specs.unlockAndCommit();
rescanDataSpecs();
@@ -303,34 +290,34 @@ bool Project::disableDataSpecs(const std::vector<SystemString>& specs) {
class CookProgress {
const hecl::MultiProgressPrinter& m_progPrinter;
const SystemChar* m_dir = nullptr;
const SystemChar* m_file = nullptr;
const char* m_dir = nullptr;
const char* m_file = nullptr;
float m_prog = 0.f;
public:
CookProgress(const hecl::MultiProgressPrinter& progPrinter) : m_progPrinter(progPrinter) {}
void changeDir(const SystemChar* dir) {
void changeDir(const char* dir) {
m_dir = dir;
m_progPrinter.startNewLine();
}
void changeFile(const SystemChar* file, float prog) {
void changeFile(const char* file, float prog) {
m_file = file;
m_prog = prog;
}
void reportFile(const DataSpecEntry* specEnt) {
SystemString submsg(m_file);
submsg += _SYS_STR(" (");
std::string submsg(m_file);
submsg += " (";
submsg += specEnt->m_name.data();
submsg += _SYS_STR(')');
submsg += ')';
m_progPrinter.print(m_dir, submsg, m_prog);
}
void reportFile(const DataSpecEntry* specEnt, const SystemChar* extra) {
SystemString submsg(m_file);
submsg += _SYS_STR(" (");
void reportFile(const DataSpecEntry* specEnt, const char* extra) {
std::string submsg(m_file);
submsg += " (";
submsg += specEnt->m_name.data();
submsg += _SYS_STR(", ");
submsg += ", ";
submsg += extra;
submsg += _SYS_STR(')');
submsg += ')';
m_progPrinter.print(m_dir, submsg, m_prog);
}
void reportDirComplete() { m_progPrinter.print(m_dir, std::nullopt, 1.f); }
@@ -348,11 +335,11 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
continue;
ProjectPath cooked = path.getCookedPath(*override);
if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast"));
cooked = cooked.getWithExtension(".fast");
if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
progress.reportFile(override);
spec->doCook(path, cooked, fast, hecl::blender::SharedBlenderToken,
[&](const SystemChar* extra) { progress.reportFile(override, extra); });
[&](const char* extra) { progress.reportFile(override, extra); });
}
}
}
@@ -362,17 +349,17 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force, bool fast,
std::vector<std::unique_ptr<IDataSpec>>& specInsts, CookProgress& progress,
ClientProcess* cp) {
if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == _SYS_STR('.'))
if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == '.')
return;
if (hecl::ProjectPath(dir, _SYS_STR("!project.yaml")).isFile() &&
hecl::ProjectPath(dir, _SYS_STR("!pool.yaml")).isFile()) {
if (hecl::ProjectPath(dir, "!project.yaml").isFile() &&
hecl::ProjectPath(dir, "!pool.yaml").isFile()) {
/* Handle AudioGroup case */
VisitFile(dir, force, fast, specInsts, progress, cp);
return;
}
std::map<SystemString, ProjectPath> children;
std::map<std::string, ProjectPath> children;
dir.getDirChildren(children);
/* Pass 1: child file count */
@@ -458,7 +445,7 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
bool foundPC = false;
for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
if (projectSpec.active && projectSpec.spec.m_factory) {
if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, _SYS_STR("-PC"))) {
if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, "-PC")) {
foundPC = true;
specEntry = &projectSpec.spec;
} else if (!foundPC) {

View File

@@ -6,23 +6,23 @@
#include "hecl/FourCC.hpp"
namespace hecl {
static const SystemRegex regPATHCOMP(_SYS_STR("[/\\\\]*([^/\\\\]+)"), SystemRegex::ECMAScript | SystemRegex::optimize);
static const std::regex regPATHCOMP("[/\\\\]*([^/\\\\]+)", std::regex::ECMAScript | std::regex::optimize);
static SystemString CanonRelPath(SystemStringView path) {
static std::string CanonRelPath(std::string_view path) {
/* Tokenize Path */
std::vector<SystemString> comps;
hecl::SystemRegexMatch matches;
SystemString in(path);
std::vector<std::string> comps;
std::smatch matches;
std::string in(path);
SanitizePath(in);
for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) {
hecl::SystemRegexMatch::const_reference match = matches[1];
if (match == _SYS_STR("."))
std::smatch::const_reference match = matches[1];
if (match == ".")
continue;
else if (match == _SYS_STR("..")) {
else if (match == "..") {
if (comps.empty()) {
/* Unable to resolve outside project */
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to resolve outside project root in {}")), path);
return _SYS_STR(".");
LogModule.report(logvisor::Fatal, FMT_STRING("Unable to resolve outside project root in {}"), path);
return ".";
}
comps.pop_back();
continue;
@@ -33,78 +33,64 @@ static SystemString CanonRelPath(SystemStringView path) {
/* Emit relative path */
if (comps.size()) {
auto it = comps.begin();
SystemString retval = *it;
std::string retval = *it;
for (++it; it != comps.end(); ++it) {
if ((*it).size()) {
retval += _SYS_STR('/');
retval += '/';
retval += *it;
}
}
return retval;
}
return _SYS_STR(".");
return ".";
}
static SystemString CanonRelPath(SystemStringView path, const ProjectRootPath& projectRoot) {
static std::string CanonRelPath(std::string_view path, const ProjectRootPath& projectRoot) {
/* Absolute paths not allowed; attempt to make project-relative */
if (IsAbsolute(path))
return CanonRelPath(projectRoot.getProjectRelativeFromAbsolute(path));
return CanonRelPath(path);
}
void ProjectPath::assign(Database::Project& project, SystemStringView path) {
void ProjectPath::assign(Database::Project& project, std::string_view path) {
m_proj = &project;
SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) {
std::string usePath;
size_t pipeFind = path.rfind('|');
if (pipeFind != std::string::npos) {
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} else
usePath = path;
m_relPath = CanonRelPath(usePath, project.getProjectRootPath());
m_absPath = SystemString(project.getProjectRootPath().getAbsolutePath()) + _SYS_STR('/') + m_relPath;
m_absPath = std::string(project.getProjectRootPath().getAbsolutePath()) + '/' + m_relPath;
SanitizePath(m_relPath);
SanitizePath(m_absPath);
ComputeHash();
}
#if HECL_UCS2
void ProjectPath::assign(Database::Project& project, std::string_view path) {
std::wstring wpath = UTF8ToWide(path);
assign(project, wpath);
}
#endif
void ProjectPath::assign(const ProjectPath& parentPath, SystemStringView path) {
void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) {
m_proj = parentPath.m_proj;
SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) {
std::string usePath;
size_t pipeFind = path.rfind('|');
if (pipeFind != std::string::npos) {
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} else
usePath = path;
m_relPath = CanonRelPath(parentPath.m_relPath + _SYS_STR('/') + usePath);
m_absPath = SystemString(m_proj->getProjectRootPath().getAbsolutePath()) + _SYS_STR('/') + m_relPath;
m_relPath = CanonRelPath(parentPath.m_relPath + '/' + usePath);
m_absPath = std::string(m_proj->getProjectRootPath().getAbsolutePath()) + '/' + m_relPath;
SanitizePath(m_relPath);
SanitizePath(m_absPath);
ComputeHash();
}
#if HECL_UCS2
void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) {
std::wstring wpath = UTF8ToWide(path);
assign(parentPath, wpath);
}
#endif
ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) const {
ProjectPath ProjectPath::getWithExtension(const char* ext, bool replace) const {
ProjectPath pp(*this);
if (replace) {
auto relIt = pp.m_relPath.end();
@@ -113,11 +99,11 @@ ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) c
auto absIt = pp.m_absPath.end();
if (absIt != pp.m_absPath.begin())
--absIt;
while (relIt != pp.m_relPath.begin() && *relIt != _SYS_STR('.') && *relIt != _SYS_STR('/')) {
while (relIt != pp.m_relPath.begin() && *relIt != '.' && *relIt != '/') {
--relIt;
--absIt;
}
if (*relIt == _SYS_STR('.') && relIt != pp.m_relPath.begin()) {
if (*relIt == '.' && relIt != pp.m_relPath.begin()) {
pp.m_relPath.resize(relIt - pp.m_relPath.begin());
pp.m_absPath.resize(absIt - pp.m_absPath.begin());
}
@@ -136,7 +122,7 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons
ProjectPath ret(m_proj->getProjectCookedPath(spec), woExt.getRelativePath());
if (getAuxInfo().size())
return ret.getWithExtension((SystemString(_SYS_STR(".")) + getAuxInfo().data()).c_str());
return ret.getWithExtension((std::string(".") + getAuxInfo().data()).c_str());
else
return ret;
}
@@ -144,7 +130,7 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons
ProjectPath::Type ProjectPath::getPathType() const {
if (m_absPath.empty())
return Type::None;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos)
if (m_absPath.find('*') != std::string::npos)
return Type::Glob;
Sstat theStat;
if (hecl::Stat(m_absPath.c_str(), &theStat))
@@ -159,7 +145,7 @@ ProjectPath::Type ProjectPath::getPathType() const {
Time ProjectPath::getModtime() const {
Sstat theStat;
time_t latestTime = 0;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) {
if (m_absPath.find('*') != std::string::npos) {
std::vector<ProjectPath> globResults;
getGlobResults(globResults);
for (ProjectPath& path : globResults) {
@@ -184,21 +170,21 @@ Time ProjectPath::getModtime() const {
return Time(latestTime);
}
}
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("invalid path type for computing modtime in '{}'")), m_absPath);
LogModule.report(logvisor::Fatal, FMT_STRING("invalid path type for computing modtime in '{}'"), m_absPath);
return Time();
}
static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& outPaths, const SystemString& remPath,
const SystemString& itStr, bool needSlash) {
SystemRegexMatch matches;
static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& outPaths, const std::string& remPath,
const std::string& itStr, bool needSlash) {
std::smatch matches;
if (!std::regex_search(remPath, matches, regPATHCOMP))
return;
const SystemString& comp = matches[1];
if (comp.find(_SYS_STR('*')) == SystemString::npos) {
SystemString nextItStr = itStr;
const std::string& comp = matches[1];
if (comp.find('*') == std::string::npos) {
std::string nextItStr = itStr;
if (needSlash)
nextItStr += _SYS_STR('/');
nextItStr += '/';
nextItStr += comp;
hecl::Sstat theStat;
@@ -213,12 +199,12 @@ static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& ou
}
/* Compile component into regex */
SystemRegex regComp(comp, SystemRegex::ECMAScript);
std::regex regComp(comp, std::regex::ECMAScript);
hecl::DirectoryEnumerator de(itStr, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de) {
if (std::regex_match(ent.m_name, regComp)) {
SystemString nextItStr = itStr;
std::string nextItStr = itStr;
if (needSlash)
nextItStr += '/';
nextItStr += ent.m_name;
@@ -235,7 +221,7 @@ static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& ou
}
}
void ProjectPath::getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const {
void ProjectPath::getDirChildren(std::map<std::string, ProjectPath>& outPaths) const {
hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de)
outPaths[ent.m_name] = ProjectPath(*this, ent.m_name);
@@ -247,7 +233,7 @@ hecl::DirectoryEnumerator ProjectPath::enumerateDir() const {
void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const {
auto rootPath = m_proj->getProjectRootPath().getAbsolutePath();
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/'));
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != '/');
}
template <typename T>
@@ -265,18 +251,18 @@ static bool RegexSearchLast(const T& str, std::match_results<typename T::const_i
return true;
}
static const hecl::SystemRegex regParsedHash32(_SYS_STR(R"(_([0-9a-fA-F]{8}))"),
static const std::regex regParsedHash32(R"(_([0-9a-fA-F]{8}))",
std::regex::ECMAScript | std::regex::optimize);
uint32_t ProjectPath::parsedHash32() const {
if (!m_auxInfo.empty()) {
hecl::SystemRegexMatch match;
std::smatch match;
if (RegexSearchLast(m_auxInfo, match, regParsedHash32)) {
auto hexStr = match[1].str();
if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16))
return val;
}
} else {
hecl::SystemViewRegexMatch match;
std::match_results<std::string_view::const_iterator> match;
if (RegexSearchLast(getLastComponent(), match, regParsedHash32)) {
auto hexStr = match[1].str();
if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16))
@@ -286,17 +272,17 @@ uint32_t ProjectPath::parsedHash32() const {
return hash().val32();
}
ProjectRootPath SearchForProject(SystemStringView path) {
ProjectRootPath SearchForProject(std::string_view path) {
ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end();
while (begin != end) {
SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
std::string testPath(begin, end);
std::string testIndexPath = testPath + "/.hecl/beacon";
Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) {
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), "rb");
if (fp == nullptr) {
continue;
}
@@ -316,7 +302,7 @@ ProjectRootPath SearchForProject(SystemStringView path) {
}
}
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
while (begin != end && *(end - 1) != '/' && *(end - 1) != '\\')
--end;
if (begin != end)
--end;
@@ -324,19 +310,19 @@ ProjectRootPath SearchForProject(SystemStringView path) {
return ProjectRootPath();
}
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
ProjectRootPath SearchForProject(std::string_view path, std::string& subpathOut) {
const ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end();
while (begin != end) {
SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
std::string testPath(begin, end);
std::string testIndexPath = testPath + "/.hecl/beacon";
Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) {
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), "rb");
if (fp == nullptr) {
continue;
}
@@ -352,10 +338,10 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
const ProjectRootPath newRootPath = ProjectRootPath(testPath);
const auto origEnd = testRoot.getAbsolutePath().end();
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\')) {
while (end != origEnd && *end != '/' && *end != '\\') {
++end;
}
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) {
if (end != origEnd && (*end == '/' || *end == '\\')) {
++end;
}
@@ -364,7 +350,7 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
}
}
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\')) {
while (begin != end && *(end - 1) != '/' && *(end - 1) != '\\') {
--end;
}
if (begin != end) {

View File

@@ -15,22 +15,22 @@ using namespace Windows::Storage;
namespace hecl::Runtime {
static logvisor::Module Log("FileStoreManager");
FileStoreManager::FileStoreManager(SystemStringView domain) : m_domain(domain) {
FileStoreManager::FileStoreManager(std::string_view domain) : m_domain(domain) {
#if _WIN32
#if !WINDOWS_STORE
WCHAR home[MAX_PATH];
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, home)))
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to locate profile for file store")));
Log.report(logvisor::Fatal, FMT_STRING("unable to locate profile for file store"));
SystemString path(home);
std::string path = nowide::narrow(home);
#else
StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
SystemString path(cacheFolder->Path->Data());
std::string path(cacheFolder->Path->Data());
#endif
path += _SYS_STR("/.heclrun");
path += "/.heclrun";
hecl::MakeDir(path.c_str());
path += _SYS_STR('/');
path += '/';
path += domain.data();
hecl::MakeDir(path.c_str());

View File

@@ -2,7 +2,7 @@
#include "hecl/hecl.hpp"
#ifdef WIN32
#include <winreg.h>
#define PATH_SEP L'\\'
#define PATH_SEP '\\'
#else
#define PATH_SEP '/'
#endif
@@ -12,25 +12,25 @@ namespace hecl {
/* Used to extract alternate steam install directories from libraryfolders.vdf */
static const std::regex regSteamPath(R"(^\s+\"[0-9]+\"\s+\"(.*)\")", std::regex::ECMAScript | std::regex::optimize);
hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
hecl::SystemString steamInstallDir;
std::string FindCommonSteamApp(const char* name) {
std::string steamInstallDir;
hecl::Sstat theStat;
#ifdef WIN32
#if !WINDOWS_STORE
HKEY hkey;
hecl::SystemChar _steamInstallDir[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE, &hkey) !=
wchar_t _steamInstallDir[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hkey) !=
ERROR_SUCCESS) {
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY,
&hkey) != ERROR_SUCCESS)
return {};
}
DWORD size = MAX_PATH;
if (RegQueryValueEx(hkey, _SYS_STR("InstallPath"), nullptr, nullptr, (LPBYTE)_steamInstallDir, &size) ==
if (RegQueryValueEx(hkey, L"InstallPath", nullptr, nullptr, (LPBYTE)_steamInstallDir, &size) ==
ERROR_SUCCESS)
steamInstallDir = _steamInstallDir;
steamInstallDir = nowide::narrow(_steamInstallDir);
RegCloseKey(hkey);
if (steamInstallDir.empty())
@@ -57,18 +57,18 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
#endif
const hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
const std::string appPath = std::string("common") + PATH_SEP + name;
/* Try main steam install directory first */
const hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
const hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
const std::string steamAppsMain = steamInstallDir + PATH_SEP + "steamapps";
const std::string mainAppPath = steamAppsMain + PATH_SEP + appPath;
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
return mainAppPath;
}
/* Iterate alternate steam install dirs */
const hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
const std::string libraryFoldersVdfPath = steamAppsMain + PATH_SEP + "libraryfolders.vdf";
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), "r");
if (fp == nullptr) {
return {};
}
@@ -88,9 +88,8 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
const auto end = fileBuf.cend();
while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
const std::string match = dirMatch[1].str();
const hecl::SystemStringConv otherInstallDir(match);
const auto otherAppPath =
hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath;
std::string(match.c_str()) + PATH_SEP + "steamapps" + PATH_SEP + appPath;
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
return otherAppPath;

View File

@@ -4,21 +4,6 @@
namespace hecl {
static logvisor::Module Log("hecl-wsconv");
std::string WideToUTF8(std::wstring_view src) {
std::string retval;
retval.reserve(src.length());
for (wchar_t ch : src) {
utf8proc_uint8_t mb[4];
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
if (c < 0) {
Log.report(logvisor::Warning, FMT_STRING("invalid UTF-8 character while encoding"));
return retval;
}
retval.append(reinterpret_cast<char*>(mb), c);
}
return retval;
}
std::string Char16ToUTF8(std::u16string_view src) {
std::string retval;
retval.reserve(src.length());
@@ -34,23 +19,6 @@ std::string Char16ToUTF8(std::u16string_view src) {
return retval;
}
std::wstring UTF8ToWide(std::string_view src) {
std::wstring retval;
retval.reserve(src.length());
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
while (*buf) {
utf8proc_int32_t wc;
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
if (len < 0) {
Log.report(logvisor::Warning, FMT_STRING("invalid UTF-8 character while decoding"));
return retval;
}
buf += len;
retval += wchar_t(wc);
}
return retval;
}
std::u16string UTF8ToChar16(std::string_view src) {
std::u16string retval;
retval.reserve(src.length());

View File

@@ -28,6 +28,7 @@
#include <sys/wait.h>
#endif
#include <ranges>
#include <logvisor/logvisor.hpp>
using namespace std::literals;
@@ -66,44 +67,14 @@ void SanitizePath(std::string& path) {
path.pop_back();
}
constexpr std::wstring_view WIllegals = L"<>?\""sv;
void SanitizePath(std::wstring& path) {
if (path.empty())
return;
path.erase(std::remove(path.begin(), path.end(), L'\n'), path.end());
path.erase(std::remove(path.begin(), path.end(), L'\r'), path.end());
std::wstring::iterator p1 = path.begin();
bool ic = false;
std::transform(path.begin(), path.end(), path.begin(), [&](const wchar_t a) -> wchar_t {
++p1;
if (WIllegals.find_first_of(a) != std::wstring::npos) {
ic = false;
return L'_';
}
if (ic) {
ic = false;
return a;
}
if (a == L'\\' && (p1 == path.end() || *p1 != L'\\')) {
ic = true;
return L'/';
}
return a;
});
while (path.back() == L'/')
path.pop_back();
}
SystemString GetcwdStr() {
std::string GetcwdStr() {
/* http://stackoverflow.com/a/2869667 */
// const size_t ChunkSize=255;
// const int MaxChunks=10240; // 2550 KiBs of current path are more than enough
SystemChar stackBuffer[255]; // Stack buffer for the "normal" case
char stackBuffer[255]; // Stack buffer for the "normal" case
if (Getcwd(stackBuffer, int(std::size(stackBuffer))) != nullptr) {
return SystemString(stackBuffer);
return std::string(stackBuffer);
}
if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it
@@ -115,9 +86,9 @@ SystemString GetcwdStr() {
// With boost use scoped_ptr; in C++0x, use unique_ptr
// If you want to be less C++ but more efficient you may want to use realloc
const int bufSize = 255 * chunks;
std::unique_ptr<SystemChar[]> cwd(new SystemChar[bufSize]);
std::unique_ptr<char[]> cwd(new char[bufSize]);
if (Getcwd(cwd.get(), bufSize) != nullptr) {
return SystemString(cwd.get());
return std::string(cwd.get());
}
if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it
@@ -125,8 +96,9 @@ SystemString GetcwdStr() {
// Of course you may choose a different error reporting method
}
}
LogModule.report(logvisor::Fatal, FMT_STRING("Cannot determine the current path; the path is apparently unreasonably long"));
return SystemString();
LogModule.report(logvisor::Fatal,
FMT_STRING("Cannot determine the current path; the path is apparently unreasonably long"));
return std::string();
}
static std::mutex PathsMutex;
@@ -160,7 +132,7 @@ void ResourceLock::ClearThreadRes() {
}
bool IsPathPNG(const hecl::ProjectPath& path) {
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), "rb");
if (fp == nullptr) {
return false;
}
@@ -176,10 +148,10 @@ bool IsPathPNG(const hecl::ProjectPath& path) {
bool IsPathBlend(const hecl::ProjectPath& path) {
const auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty() || lastCompExt != _SYS_STR("blend"))
if (lastCompExt.empty() || lastCompExt != "blend")
return false;
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), "rb");
if (fp == nullptr) {
return false;
}
@@ -195,132 +167,162 @@ bool IsPathBlend(const hecl::ProjectPath& path) {
bool IsPathYAML(const hecl::ProjectPath& path) {
auto lastComp = path.getLastComponent();
if (lastComp == _SYS_STR("!catalog.yaml") ||
lastComp == _SYS_STR("!memoryid.yaml") ||
lastComp == _SYS_STR("!memoryrelays.yaml"))
if (lastComp == "!catalog.yaml" || lastComp == "!memoryid.yaml" || lastComp == "!memoryrelays.yaml")
return false; /* !catalog.yaml, !memoryid.yaml, !memoryrelays.yaml are exempt from general use */
auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty())
return false;
return lastCompExt == _SYS_STR("yaml") || lastCompExt == _SYS_STR("yml");
return lastCompExt == "yaml" || lastCompExt == "yml";
}
hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse,
hecl::DirectoryEnumerator::DirectoryEnumerator(std::string_view path, Mode mode, bool sizeSort, bool reverse,
bool noHidden) {
hecl::Sstat theStat;
if (hecl::Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
Sstat theStat;
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode)) {
return;
}
#if _WIN32
hecl::SystemString wc(path);
wc += _SYS_STR("/*");
std::wstring wc = nowide::widen(path);
wc += L"/*";
WIN32_FIND_DATAW d;
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE)
if (dir == INVALID_HANDLE_VALUE) {
return;
}
switch (mode) {
case Mode::Native:
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st))
continue;
size_t sz = 0;
bool isDir = false;
if (S_ISDIR(st.st_mode))
if (S_ISDIR(st.st_mode)) {
isDir = true;
else if (S_ISREG(st.st_mode))
} else if (S_ISREG(st.st_mode)) {
sz = st.st_size;
else
} else {
continue;
}
m_entries.emplace_back(fp, d.cFileName, sz, isDir);
m_entries.emplace_back(fp, fileName, sz, isDir);
} while (FindNextFileW(dir, &d));
break;
case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) {
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
}
sort.emplace(fileName, Entry{fp, fileName, 0, true});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(sort.size());
if (reverse) {
for (auto& it : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(it.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
if (mode == Mode::DirsSorted)
if (mode == Mode::DirsSorted) {
break;
}
FindClose(dir);
dir = FindFirstFileW(wc.c_str(), &d);
}
case Mode::FilesSorted: {
if (mode == Mode::FilesSorted)
if (mode == Mode::FilesSorted) {
m_entries.clear();
}
if (sizeSort) {
std::multimap<size_t, Entry> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
continue;
sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
}
sort.emplace(st.st_size, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(m_entries.size() + sort.size());
if (reverse) {
for (auto& it : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(it.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
} else {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
}
sort.emplace(fileName, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(m_entries.size() + sort.size());
if (reverse) {
for (auto& e : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(e.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
}
break;
@@ -341,7 +343,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -362,13 +364,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
break;
case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -400,7 +402,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -416,13 +418,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
} else {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -447,159 +449,24 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
#endif
}
static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) {
hecl::SystemUTF8Conv utf8(path);
if (utf8.str().size() == 1 && utf8.str()[0] == '/')
return {hecl::SystemString(path), "/"};
size_t lastSlash = utf8.str().rfind('/');
static std::pair<std::string, std::string> NameFromPath(std::string_view path) {
if (path.size() == 1 && path[0] == '/')
return {std::string(path), "/"};
size_t lastSlash = path.rfind('/');
if (lastSlash != std::string::npos)
return {hecl::SystemString(path), std::string(utf8.str().cbegin() + lastSlash + 1, utf8.str().cend())};
return {std::string(path), std::string(path.cbegin() + lastSlash + 1, path.cend())};
else
return {hecl::SystemString(path), std::string(utf8.str())};
return {std::string(path), std::string(path)};
}
std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
std::vector<std::pair<hecl::SystemString, std::string>> ret;
#ifdef WIN32
#if !WINDOWS_STORE
/* Add the drive names to the listing (as queried by blender) */
{
constexpr uint32_t FILE_MAXDIR = 768;
wchar_t wline[FILE_MAXDIR];
const uint32_t tmp = GetLogicalDrives();
for (uint32_t i = 0; i < 26; i++) {
if ((tmp >> i) & 1) {
wline[0] = L'A' + i;
wline[1] = L':';
wline[2] = L'/';
wline[3] = L'\0';
wchar_t* name = nullptr;
/* Flee from horrible win querying hover floppy drives! */
if (i > 1) {
/* Try to get volume label as well... */
if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) {
const size_t labelLen = std::wcslen(wline + 4);
_snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline);
name = wline + 4;
}
}
wline[2] = L'\0';
if (name == nullptr) {
ret.push_back(NameFromPath(wline));
} else {
ret.emplace_back(wline, hecl::WideToUTF8(name));
}
}
}
/* Adding Desktop and My Documents */
SystemString wpath;
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_PERSONAL, 0);
wpath.assign(wline);
SanitizePath(wpath);
ret.push_back(NameFromPath(wpath));
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_DESKTOPDIRECTORY, 0);
wpath.assign(wline);
SanitizePath(wpath);
ret.push_back(NameFromPath(wpath));
}
#endif
#else
#ifdef __APPLE__
{
hecl::Sstat theStat;
const char* home = getenv("HOME");
if (home) {
ret.push_back(NameFromPath(home));
std::string desktop(home);
desktop += "/Desktop";
if (!hecl::Stat(desktop.c_str(), &theStat))
ret.push_back(NameFromPath(desktop));
}
/* Get mounted volumes better method OSX 10.6 and higher, see: */
/*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/
/* we get all volumes sorted including network and do not relay on user-defined finder visibility, less confusing */
CFURLRef cfURL = nullptr;
CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
CFURLEnumeratorRef volEnum =
CFURLEnumeratorCreateForMountedVolumes(nullptr, kCFURLEnumeratorSkipInvisibles, nullptr);
while (result != kCFURLEnumeratorEnd) {
char defPath[1024];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, nullptr);
if (result != kCFURLEnumeratorSuccess) {
continue;
}
CFURLGetFileSystemRepresentation(cfURL, false, reinterpret_cast<UInt8*>(defPath), std::size(defPath));
ret.push_back(NameFromPath(defPath));
}
CFRelease(volEnum);
}
#else
/* unix */
{
hecl::Sstat theStat;
const char* home = getenv("HOME");
if (home) {
ret.push_back(NameFromPath(home));
std::string desktop(home);
desktop += "/Desktop";
if (!hecl::Stat(desktop.c_str(), &theStat))
ret.push_back(NameFromPath(desktop));
}
{
bool found = false;
#ifdef __linux__
/* Loop over mount points */
struct mntent* mnt;
FILE* fp = setmntent(MOUNTED, "r");
if (fp) {
while ((mnt = getmntent(fp))) {
if (strlen(mnt->mnt_fsname) < 4 || strncmp(mnt->mnt_fsname, "/dev", 4))
continue;
std::string mntStr(mnt->mnt_dir);
if (mntStr.size() > 1 && mntStr.back() == '/')
mntStr.pop_back();
ret.push_back(NameFromPath(mntStr));
found = true;
}
endmntent(fp);
}
#endif
/* Fallback */
if (!found)
ret.push_back(NameFromPath("/"));
}
}
#endif
#endif
return ret;
}
std::wstring Char16ToWide(std::u16string_view src) { return std::wstring(src.begin(), src.end()); }
/* recursive mkdir */
#if _WIN32
int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024];
int RecursiveMakeDir(const char* dir) {
char tmp[1024];
/* copy path */
std::wcsncpy(tmp, dir, std::size(tmp));
const size_t len = std::wcslen(tmp);
std::strncpy(tmp, dir, std::size(tmp));
const size_t len = std::strlen(tmp);
if (len >= std::size(tmp)) {
return -1;
}
@@ -610,7 +477,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
/* recursive mkdir */
SystemChar* p = nullptr;
char* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) {
if (*p == '/' || *p == '\\') {
@@ -618,7 +485,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
/* test path */
if (Stat(tmp, &sb) != 0) {
/* path does not exist - create directory */
if (!CreateDirectoryW(tmp, nullptr)) {
const nowide::wstackstring wtmp(tmp);
if (!CreateDirectoryW(wtmp.get(), nullptr)) {
return -1;
}
} else if (!S_ISDIR(sb.st_mode)) {
@@ -631,7 +499,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
/* test path */
if (Stat(tmp, &sb) != 0) {
/* path does not exist - create directory */
if (!CreateDirectoryW(tmp, nullptr)) {
const nowide::wstackstring wtmp(tmp);
if (!CreateDirectoryW(wtmp.get(), nullptr)) {
return -1;
}
} else if (!S_ISDIR(sb.st_mode)) {
@@ -641,8 +510,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
return 0;
}
#else
int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024];
int RecursiveMakeDir(const char* dir) {
char tmp[1024];
/* copy path */
std::memset(tmp, 0, std::size(tmp));
@@ -658,7 +527,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
/* recursive mkdir */
SystemChar* p = nullptr;
char* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
@@ -690,25 +559,27 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
#endif
const SystemChar* GetTmpDir() {
std::string GetTmpDir() {
#ifdef _WIN32
#if WINDOWS_STORE
const wchar_t* TMPDIR = nullptr;
#else
const wchar_t* TMPDIR = _wgetenv(L"TEMP");
if (!TMPDIR)
TMPDIR = L"\\Temp";
auto TMPDIR = GetEnv("TEMP");
if (!TMPDIR) {
return "\\Temp";
}
return std::move(TMPDIR.value());
#endif
#else
const char* TMPDIR = getenv("TMPDIR");
if (!TMPDIR)
TMPDIR = "/tmp";
#endif
return TMPDIR;
#endif
}
#if !WINDOWS_STORE
int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
int RunProcess(const char* path, const char* const args[]) {
#ifdef _WIN32
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
HANDLE consoleOutReadTmp = INVALID_HANDLE_VALUE;
@@ -741,12 +612,12 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
CloseHandle(consoleOutReadTmp);
hecl::SystemString cmdLine;
const SystemChar* const* arg = &args[1];
std::wstring cmdLine;
const char* const* arg = &args[1];
while (*arg) {
cmdLine += _SYS_STR(" \"");
cmdLine += *arg++;
cmdLine += _SYS_STR('"');
cmdLine += L" \"";
cmdLine += nowide::widen(*arg++);
cmdLine += L'"';
}
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
@@ -758,12 +629,14 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
sinfo.hStdOutput = consoleOutWrite;
PROCESS_INFORMATION pinfo = {};
if (!CreateProcessW(path, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &sinfo,
&pinfo)) {
const nowide::wstackstring wpath(path);
if (!CreateProcessW(wpath.get(), cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
&sinfo, &pinfo)) {
LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
LogModule.report(logvisor::Error, FMT_STRING(L"unable to launch process from {}: {}"), path, messageBuffer);
LogModule.report(logvisor::Error, FMT_STRING("unable to launch process from {}: {}"), path,
nowide::narrow(messageBuffer));
LocalFree(messageBuffer);
CloseHandle(nulHandle);