Fix cases where ANSI filename can be handled incorrectly on Windows

This commit is contained in:
Ivan Savenko
2026-09-05 18:15:21 +03:00
parent ee2f52eebe
commit 6da50ddd45
37 changed files with 115 additions and 84 deletions
+2 -1
View File
@@ -74,6 +74,7 @@
#include "../lib/CConfigHandler.h"
#include "../lib/GameLibrary.h"
#include "../lib/texts/CGeneralTextHandler.h"
#include "../lib/texts/TextOperations.h"
#include "../lib/CPlayerState.h"
#include "../lib/CRandomGenerator.h"
#include "../lib/CStack.h"
@@ -1641,7 +1642,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
{
if (is_regular_file(dir->status()))
{
std::string name = dir->path().filename().string();
std::string name = TextOperations::filesystemPathToUtf8(dir->path().filename());
if (starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
{
char nr = name[namePrefix.size()];
+5 -4
View File
@@ -46,6 +46,7 @@
#include "../lib/modding/ModUtility.h"
#include "../lib/serializer/GameConnection.h"
#include "../lib/VCMIDirs.h"
#include "../lib/texts/TextOperations.h"
#include "../lib/ObstacleHandler.h"
#include "../lib/logging/VisualLogger.h"
@@ -223,7 +224,7 @@ void ClientCommandManager::handleTranslateGameCommand(bool onlyMissing)
}
printCommandMessage("Translation export complete");
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
printCommandMessage("Extracted files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory\n");
}
void ClientCommandManager::handleTranslateMapsCommand()
@@ -306,7 +307,7 @@ void ClientCommandManager::handleTranslateMapsCommand()
}
printCommandMessage("Translation export complete");
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
printCommandMessage("Extracted files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory\n");
}
@@ -348,7 +349,7 @@ void ClientCommandManager::handleGetConfigCommand()
}
printCommandMessage("\rExtracting done :)\n");
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
printCommandMessage("Extracted files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory\n");
}
void ClientCommandManager::handleAntilagCommand(std::istringstream& singleWordBuffer)
@@ -400,7 +401,7 @@ void ClientCommandManager::handleGetTextCommand()
}
printCommandMessage("\rExtracting done :)\n");
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
printCommandMessage("Extracted files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory\n");
}
void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBuffer)
+2 -1
View File
@@ -17,6 +17,7 @@
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/json/JsonUtils.h"
#include "../../lib/texts/TextOperations.h"
bool CAnimation::loadFrame(size_t frame, size_t group, bool verbose)
{
@@ -93,7 +94,7 @@ void CAnimation::exportBitmaps(const boost::filesystem::path& path) const
}
}
logGlobal->info("Exported %d frames to %s", counter, actualPath.string());
logGlobal->info("Exported %d frames to %s", counter, TextOperations::filesystemPathToUtf8(actualPath));
}
void CAnimation::printError(size_t frame, size_t group, std::string type) const
+3 -2
View File
@@ -36,6 +36,7 @@
#include "../lib/filesystem/Filesystem.h"
#include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/modding/IdentifierStorage.h"
#include "../lib/texts/TextOperations.h"
#include "../lib/modding/CModHandler.h"
#include "../lib/modding/ModDescription.h"
#include "../lib/texts/CGeneralTextHandler.h"
@@ -252,7 +253,7 @@ int main(int argc, char * argv[])
logConfigurator.configureDefault();
logGlobal->info("Starting client of '%s'", GameConstants::VCMI_PROJECT_NAME_VERSIONED);
logGlobal->info("Creating console and configuring logger: %d ms", pomtime.getDiff());
logGlobal->info("The log file will be saved to %s", logPath);
logGlobal->info("The log file will be saved to %s", TextOperations::filesystemPathToUtf8(logPath));
// Init filesystem and settings
try
@@ -321,7 +322,7 @@ int main(int argc, char * argv[])
testFile("DATA/HELP.TXT", "VCMI requires Heroes III: Shadow of Death or Heroes III: Complete data files to run!");
testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted!\nBuilt-in mod was not found!");
testFile("DATA/NOTOSERIF-MEDIUM.TTF", "VCMI installation is corrupted!\nBuilt-in font was not found!\nManually deleting '" + VCMIDirs::get().userDataPath().string() + "/Mods/VCMI' directory (if it exists)\nor clearing app data and reimporting Heroes III files may fix this problem.");
testFile("DATA/NOTOSERIF-MEDIUM.TTF", "VCMI installation is corrupted!\nBuilt-in font was not found!\nManually deleting '" + TextOperations::filesystemPathToUtf8(VCMIDirs::get().userDataPath()) + "/Mods/VCMI' directory (if it exists)\nor clearing app data and reimporting Heroes III files may fix this problem.");
testFile("DATA/PLAYERS.PAL", "Heroes III data files (Data/H3Bitmap.lod) are incomplete or corruped!\n Please reinstall them.");
testFile("SPRITES/DEFAULT.DEF", "Heroes III data files (Data/H3Sprite.lod) are incomplete or corruped!\n Please reinstall them.");
+3 -1
View File
@@ -16,6 +16,8 @@
#include "SDLImageScaler.h"
#include "SDLImage.h"
#include "lib/texts/TextOperations.h"
#include <SDL_image.h>
#include <SDL_surface.h>
@@ -50,7 +52,7 @@ void CanvasImage::scaleTo(const Point & size, EScalingAlgorithm algorithm)
void CanvasImage::exportBitmap(const boost::filesystem::path & path) const
{
IMG_SavePNG(surface, path.string().c_str());
IMG_SavePNG(surface, TextOperations::filesystemPathToUtf8(path).c_str());
}
Canvas CanvasImage::getCanvas()
+2 -1
View File
@@ -23,6 +23,7 @@
#include "lib/AsyncRunner.h"
#include "lib/CConfigHandler.h"
#include "lib/texts/TextOperations.h"
#include <tbb/parallel_for.h>
@@ -343,7 +344,7 @@ void SDLImageShared::exportBitmap(const boost::filesystem::path& path, SDL_Palet
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
IMG_SavePNG(surf, path.string().c_str());
IMG_SavePNG(surf, TextOperations::filesystemPathToUtf8(path).c_str());
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, originalPalette);
}
+2 -1
View File
@@ -28,6 +28,7 @@
#include "lib/constants/StringConstants.h"
#include "lib/VCMIDirs.h"
#include "lib/texts/MetaString.h"
#include "lib/texts/TextOperations.h"
#include <vstd/DateUtils.h>
@@ -750,7 +751,7 @@ void ScreenHandler::screenShot() const
img->exportBitmap(filePath, nullptr);
MetaString txt;
txt.appendTextID("vcmi.client.screenShot");
txt.replaceRawString(filePath.string());
txt.replaceRawString(TextOperations::filesystemPathToUtf8(filePath));
if(GAME->interface())
GAME->server().getGameChat().sendMessageGameplay(txt.toString(&GAME->translator()));
}
+3 -1
View File
@@ -18,6 +18,8 @@
#include "SDLImageScaler.h"
#include "SDLImage.h"
#include "lib/texts/TextOperations.h"
#include <SDL3_image/SDL_image.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
@@ -90,7 +92,7 @@ void CanvasImage::scaleTo(const Point & size, EScalingAlgorithm algorithm)
void CanvasImage::exportBitmap(const boost::filesystem::path & path) const
{
IMG_SavePNG(surface, path.string().c_str());
IMG_SavePNG(surface, TextOperations::filesystemPathToUtf8(path).c_str());
}
Canvas CanvasImage::getCanvas()
+2 -1
View File
@@ -25,6 +25,7 @@
#include "lib/AsyncRunner.h"
#include "lib/CConfigHandler.h"
#include "lib/texts/TextOperations.h"
#include <tbb/parallel_for.h>
@@ -501,7 +502,7 @@ void SDLImageShared::exportBitmap(const boost::filesystem::path& path, SDL_Palet
if (palette && CSDL_Ext::getPalette(surf))
SDL_SetSurfacePalette(surf, palette);
IMG_SavePNG(surf, path.string().c_str());
IMG_SavePNG(surf, TextOperations::filesystemPathToUtf8(path).c_str());
if (palette && CSDL_Ext::getPalette(surf))
SDL_SetSurfacePalette(surf, originalPalette);
}
+2 -1
View File
@@ -30,6 +30,7 @@
#include "lib/constants/StringConstants.h"
#include "lib/VCMIDirs.h"
#include "lib/texts/MetaString.h"
#include "lib/texts/TextOperations.h"
#include <vstd/DateUtils.h>
@@ -1018,7 +1019,7 @@ void ScreenHandler::screenShot() const
img->exportBitmap(filePath, nullptr);
MetaString txt;
txt.appendTextID("vcmi.client.screenShot");
txt.replaceRawString(filePath.string());
txt.replaceRawString(TextOperations::filesystemPathToUtf8(filePath));
if(GAME->interface())
GAME->server().getGameChat().sendMessageGameplay(txt.toString(&GAME->translator()));
}
+1 -1
View File
@@ -172,7 +172,7 @@ void DemoInstaller::install(QString filename)
CCompressedStream innerStream(std::move(innerMem), true);
QByteArray fileData = readStreamFully(innerStream);
QDir dir(QString::fromStdString(VCMIDirs::get().userDataPath().string()));
QDir dir(pathToQString(VCMIDirs::get().userDataPath()));
QString folder = fileEntry.name.split("/")[0];
if(!dir.exists(folder))
dir.mkpath(folder);
+1 -1
View File
@@ -453,7 +453,7 @@ void MainWindow::manualInstallFile(QString filePath)
}
else if(realFilePath.endsWith(".json", Qt::CaseInsensitive))
{
QDir configDir(QString::fromStdString(VCMIDirs::get().userConfigPath().string()));
QDir configDir(pathToQString(VCMIDirs::get().userConfigPath()));
QStringList configFile = configDir.entryList({fileName}, QDir::Filter::Files); // case insensitive check
if(!configFile.empty())
{
+1 -1
View File
@@ -185,7 +185,7 @@ void ChroniclesExtractor::extractFiles(int no) const
if(scrDir.entryList({file}).isEmpty())
return; // file does not exists (needed for "All in one" installer)
CArchiveLoader archive("", scrDir.filePath(scrDir.entryList({file}).front()).toStdString(), false);
CArchiveLoader archive("", qstringToPath(scrDir.filePath(scrDir.entryList({file}).front())), false);
for(auto & entry : archive.getEntries())
if(files.empty())
archive.extractToFolder(dest.absolutePath().toStdString(), "", entry.second, true);
@@ -133,7 +133,7 @@ void ConfigEditorDialog::onSaveButtonClicked()
QString ConfigEditorDialog::loadFile(QString filename)
{
auto file = pathToQString(VCMIDirs::get().userConfigPath() / filename.toStdString());
auto file = pathToQString(VCMIDirs::get().userConfigPath() / qstringToPath(filename));
QFile f(file);
if(!f.open(QFile::ReadOnly | QFile::Text))
{
@@ -148,7 +148,7 @@ QString ConfigEditorDialog::loadFile(QString filename)
void ConfigEditorDialog::saveFile(QString filename, QString content)
{
auto file = pathToQString(VCMIDirs::get().userConfigPath() / filename.toStdString());
auto file = pathToQString(VCMIDirs::get().userConfigPath() / qstringToPath(filename));
QFile f(file);
if(!f.open(QFile::WriteOnly | QFile::Text))
{
+2 -1
View File
@@ -13,6 +13,7 @@
#include "CThreadHelper.h"
#include "VCMIDirs.h"
#include "texts/TextOperations.h"
#include <boost/stacktrace.hpp>
#if defined(NDEBUG) && !defined(VCMI_ANDROID)
@@ -60,7 +61,7 @@ static void createMemoryDump(MINIDUMP_EXCEPTION_INFORMATION * meinfo)
const auto dumpName = boost::filesystem::path(executablePath.data()).filename().wstring() + L"_crashinfo.dmp";
const auto dumpPath = VCMIDirs::get().userLogsPath() / dumpName;
HANDLE dfile = CreateFileW(dumpPath.c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
logGlobal->error("Crash info will be put in %s", dumpPath.string());
logGlobal->error("Crash info will be put in %s", TextOperations::filesystemPathToUtf8(dumpPath));
auto dumpType = MiniDumpWithDataSegs;
+9 -8
View File
@@ -11,6 +11,7 @@
#include "StdInc.h"
#include "VCMIDirs.h"
#include "json/JsonNode.h"
#include "texts/TextOperations.h"
#ifdef VCMI_IOS
#include "iOS_utils.h"
@@ -30,19 +31,19 @@ std::string IVCMIDirs::genHelpString() const
{
std::vector<std::string> tempVec;
for (const bfs::path & path : dataPaths())
tempVec.push_back(path.string());
tempVec.push_back(TextOperations::filesystemPathToUtf8(path));
const auto gdStringA = boost::algorithm::join(tempVec, ":");
return
" game data: " + gdStringA + "\n"
" server: " + serverPath().string() + "\n"
" server: " + TextOperations::filesystemPathToUtf8(serverPath()) + "\n"
"\n"
" user data: " + userDataPath().string() + "\n"
" user cache: " + userCachePath().string() + "\n"
" user config: " + userConfigPath().string() + "\n"
" user logs: " + userLogsPath().string() + "\n"
" user saves: " + userSavePath().string() + "\n"
" user extracted: " + userExtractedPath().string() + "\n";
" user data: " + TextOperations::filesystemPathToUtf8(userDataPath()) + "\n"
" user cache: " + TextOperations::filesystemPathToUtf8(userCachePath()) + "\n"
" user config: " + TextOperations::filesystemPathToUtf8(userConfigPath()) + "\n"
" user logs: " + TextOperations::filesystemPathToUtf8(userLogsPath()) + "\n"
" user saves: " + TextOperations::filesystemPathToUtf8(userSavePath()) + "\n"
" user extracted: " + TextOperations::filesystemPathToUtf8(userExtractedPath()) + "\n";
}
void IVCMIDirs::init()
+1 -1
View File
@@ -120,7 +120,7 @@ std::set<boost::filesystem::path> CFilesystemList::getResourceNames(const Resour
auto rn = loader->getResourceName(resourceName);
if(rn)
{
paths.insert(rn->string());
paths.insert(*rn);
}
}
return paths;
+8 -4
View File
@@ -36,7 +36,7 @@ CArchiveLoader::CArchiveLoader(std::string _mountPoint, boost::filesystem::path
return;
// Retrieve file extension of archive in uppercase
const std::string ext = boost::to_upper_copy(archive.extension().string());
const std::string ext = boost::to_upper_copy(TextOperations::filesystemPathToUtf8(archive.extension()));
// Init the specific lod container format
if(ext == ".LOD" || ext == ".PAC")
@@ -46,9 +46,9 @@ CArchiveLoader::CArchiveLoader(std::string _mountPoint, boost::filesystem::path
else if(ext == ".SND")
initSNDArchive(mountPoint, fileStream);
else
throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive.string());
throw std::runtime_error("LOD archive format unknown. Cannot deal with " + TextOperations::filesystemPathToUtf8(archive));
logGlobal->trace("%sArchive \"%s\" loaded (%d files found).", ext, archive.filename(), entries.size());
logGlobal->trace("%sArchive \"%s\" loaded (%d files found).", ext, TextOperations::filesystemPathToUtf8(archive.filename()), entries.size());
}
void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStream & fileStream)
@@ -254,7 +254,11 @@ std::time_t CArchiveLoader::getLastWriteTime(const ResourcePath& resourceName) c
boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName, bool absolute)
{
boost::filesystem::path extractionFolderPath = absolute ? outputSubFolder : VCMIDirs::get().userExtractedPath() / outputSubFolder;
// outputSubFolder is UTF-8, so it must not go through the implicit path constructor:
// on Windows that decodes it using the ANSI codepage instead.
// entryName is archive-supplied and stays on the legacy conversion
const boost::filesystem::path subFolder = TextOperations::Utf8TofilesystemPath(outputSubFolder);
boost::filesystem::path extractionFolderPath = absolute ? subFolder : VCMIDirs::get().userExtractedPath() / subFolder;
boost::filesystem::path extractedFilePath = extractionFolderPath / entryName;
boost::filesystem::create_directories(extractionFolderPath);
+2 -1
View File
@@ -11,6 +11,7 @@
#include "CFileInputStream.h"
#include "../ExceptionsCommon.h"
#include "../texts/TextOperations.h"
CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 start, si64 size)
: dataStart{start},
@@ -18,7 +19,7 @@ CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 st
fileStream{file.c_str(), std::ios::in | std::ios::binary}
{
if (fileStream.fail())
throw DataLoadingException("Failed to open file '" + file.string() + "'. Reason: " + strerror(errno) );
throw DataLoadingException("Failed to open file '" + TextOperations::filesystemPathToUtf8(file) + "'. Reason: " + strerror(errno) );
if (dataSize == 0)
{
+3 -3
View File
@@ -24,7 +24,7 @@ CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, boost::filesystem:
fileList = listFiles(mountPoint, depth, initial);
}
catch (const boost::filesystem::filesystem_error & e) {
throw DataLoadingException("Failed to load content of '" + baseDirectory.string() + "'. Reason: " + e.what());
throw DataLoadingException("Failed to load content of '" + TextOperations::filesystemPathToUtf8(baseDirectory) + "'. Reason: " + e.what());
}
logGlobal->trace("File system loaded, %d files found", fileList.size());
@@ -36,7 +36,7 @@ std::unique_ptr<CInputStream> CFilesystemLoader::load(const ResourcePath & resou
assert(fileList.contains(resourceName));
boost::filesystem::path file = baseDirectory / fileList.at(resourceName);
logGlobal->trace("loading %s", file.string());
logGlobal->trace("loading %s", TextOperations::filesystemPathToUtf8(file));
return std::make_unique<CFileInputStream>(file);
}
@@ -184,7 +184,7 @@ std::unordered_map<ResourcePath, boost::filesystem::path> CFilesystemLoader::lis
type = EResType::DIRECTORY;
}
else
type = EResTypeHelper::getTypeFromExtension(it->path().extension().string());
type = EResTypeHelper::getTypeFromExtension(TextOperations::filesystemPathToUtf8(it->path().extension()));
if (!initial || vstd::contains(initialTypes, type))
{
+4 -4
View File
@@ -67,7 +67,7 @@ std::unordered_map<ResourcePath, unz64_file_pos> CZipLoader::listFiles(const std
unzFile file = unzOpen2_64(archive.c_str(), &zlibApi);
if(file == nullptr)
logGlobal->error("%s failed to open", archive.string());
logGlobal->error("%s failed to open", TextOperations::filesystemPathToUtf8(archive));
if (unzGoToFirstFile(file) == UNZ_OK)
{
@@ -215,7 +215,7 @@ ZipArchive::ZipArchive(const boost::filesystem::path & from)
#endif
if (archive == nullptr)
throw std::runtime_error("Failed to open file '" + from.string());
throw std::runtime_error("Failed to open file '" + TextOperations::filesystemPathToUtf8(from));
}
ZipArchive::~ZipArchive()
@@ -258,9 +258,9 @@ bool ZipArchive::extract(const boost::filesystem::path & where, const std::strin
{
#ifdef VCMI_WINDOWS
if (fullName.size() < 260)
logGlobal->error("Failed to open file '%s'", fullName.string());
logGlobal->error("Failed to open file '%s'", TextOperations::filesystemPathToUtf8(fullName));
else
logGlobal->error("Failed to open file with long path '%s' (%d characters)", fullName.string(), fullName.size());
logGlobal->error("Failed to open file with long path '%s' (%d characters)", TextOperations::filesystemPathToUtf8(fullName), fullName.size());
#else
logGlobal->error("Failed to open file '%s'", fullName.c_str());
#endif
+1 -1
View File
@@ -63,7 +63,7 @@ public:
auto rn = getResourceName(resourceName);
if(rn)
{
result.insert(rn->string());
result.insert(*rn);
}
return result;
}
+3 -2
View File
@@ -11,6 +11,7 @@
#include "MinizipExtensions.h"
#include "CMemoryBuffer.h"
#include "../texts/TextOperations.h"
#include <mutex>
@@ -273,7 +274,7 @@ int ZCALLBACK CProxyIOApi::errorFileProxy(voidpf opaque, voidpf stream)
CInputOutputStream * CProxyIOApi::openFile(const boost::filesystem::path & filename, int mode)
{
logGlobal->trace("CProxyIOApi: stream opened for %s with mode %d", filename.string(), mode);
logGlobal->trace("CProxyIOApi: stream opened for %s with mode %d", TextOperations::filesystemPathToUtf8(filename), mode);
data->seek(0);
return data;
@@ -306,7 +307,7 @@ zlib_filefunc64_def CProxyROIOApi::getApiStructure()
CInputStream * CProxyROIOApi::openFile(const boost::filesystem::path& filename, int mode)
{
logGlobal->trace("CProxyROIOApi: stream opened for %s with mode %d", filename.string(), mode);
logGlobal->trace("CProxyROIOApi: stream opened for %s with mode %d", TextOperations::filesystemPathToUtf8(filename), mode);
data->seek(0);
return data;
+2 -1
View File
@@ -20,6 +20,7 @@
#include "../GameSettings.h"
#include "../texts/CGeneralTextHandler.h"
#include "../texts/TextOperations.h"
#include "../CPlayerState.h"
#include "../CStopWatch.h"
#include "../IGameSettings.h"
@@ -379,7 +380,7 @@ void CGameState::initNewGame(const IMapService * mapService, vstd::RNG & randomG
mapService->saveMap(map, fullPath);
logGlobal->info("Random map has been saved to:");
logGlobal->info(fullPath.string());
logGlobal->info(TextOperations::filesystemPathToUtf8(fullPath));
}
catch(...)
{
+2 -1
View File
@@ -12,6 +12,7 @@
#include "../CPlayerState.h"
#include "../constants/StringConstants.h"
#include "../VCMIDirs.h"
#include "../texts/TextOperations.h"
#include "CGameState.h"
#include "TerrainHandler.h"
#include "StartInfo.h"
@@ -290,7 +291,7 @@ std::string StatisticDataSet::writeCsv(const ITranslator * translator) const
std::string csv = toCsv(";", translator);
file << csv;
return filePath.string();
return TextOperations::filesystemPathToUtf8(filePath);
}
//calculates total number of artifacts that belong to given player
+4 -1
View File
@@ -97,7 +97,10 @@ uint32_t ModsState::computeChecksum(const TModID & modName) const
double ModsState::getInstalledModSizeMegabytes(const TModID & modName) const
{
ResourcePath resDir(getModDirectory(modName), EResType::DIRECTORY);
std::string path = CResourceHandler::get()->getResourceName(resDir)->string();
// iterate over the path itself - a detour through std::string would convert it using the
// Windows ANSI codepage, replacing any character the codepage lacks with '?'. The directory
// would then not exist and recursive_directory_iterator would throw
const boost::filesystem::path path = *CResourceHandler::get()->getResourceName(resDir);
size_t sizeBytes = 0;
for(boost::filesystem::recursive_directory_iterator it(path); it != boost::filesystem::recursive_directory_iterator(); ++it)
+8 -6
View File
@@ -10,6 +10,8 @@
#include "StdInc.h"
#include "CLoadFile.h"
#include "../texts/TextOperations.h"
template <typename From, typename To>
struct static_caster
{
@@ -28,22 +30,22 @@ CLoadFile::CLoadFile(const boost::filesystem::path & fname, IGameInfoCallback *
sfile.exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
if(!sfile)
throw std::runtime_error("Error: cannot open file '" + fname.string() + "' for reading!");
throw std::runtime_error("Error: cannot open file '" + TextOperations::filesystemPathToUtf8(fname) + "' for reading!");
static const std::string MAGIC = "VCMI";
std::string readMagic = MAGIC;
sfile.read(readMagic.data(), 4);
if(readMagic != MAGIC)
throw std::runtime_error("Error: '" + fname.string() + "' is not a VCMI file!");
throw std::runtime_error("Error: '" + TextOperations::filesystemPathToUtf8(fname) + "' is not a VCMI file!");
sfile.read(reinterpret_cast<char*>(&serializer.version), sizeof(serializer.version));
if(serializer.version < ESerializationVersion::MINIMAL)
throw std::runtime_error("Error: too old file format detected in '" + fname.string() + "'!");
throw std::runtime_error("Error: too old file format detected in '" + TextOperations::filesystemPathToUtf8(fname) + "'!");
if(serializer.version > ESerializationVersion::CURRENT)
{
logGlobal->warn("Warning format version mismatch: found %d when current is %d! (file %s)\n", vstd::to_underlying(serializer.version), vstd::to_underlying(ESerializationVersion::CURRENT), fname.string());
logGlobal->warn("Warning format version mismatch: found %d when current is %d! (file %s)\n", vstd::to_underlying(serializer.version), vstd::to_underlying(ESerializationVersion::CURRENT), TextOperations::filesystemPathToUtf8(fname));
auto * versionptr = reinterpret_cast<char *>(&serializer.version);
std::reverse(versionptr, versionptr + 4);
@@ -51,11 +53,11 @@ CLoadFile::CLoadFile(const boost::filesystem::path & fname, IGameInfoCallback *
if(serializer.version == ESerializationVersion::CURRENT)
{
logGlobal->warn("%s seems to have different endianness! Entering reversing mode.", fname.string());
logGlobal->warn("%s seems to have different endianness! Entering reversing mode.", TextOperations::filesystemPathToUtf8(fname));
serializer.reverseEndianness = true;
}
else
throw std::runtime_error("Error: too new file format detected in '" + fname.string() + "'!");
throw std::runtime_error("Error: too new file format detected in '" + TextOperations::filesystemPathToUtf8(fname) + "'!");
}
std::string loaded = SAVEGAME_MAGIC;
+3 -1
View File
@@ -10,6 +10,8 @@
#include "StdInc.h"
#include "CSaveFile.h"
#include "../texts/TextOperations.h"
CSaveFile::CSaveFile()
: serializer(this)
{
@@ -28,7 +30,7 @@ void CSaveFile::write(const boost::filesystem::path & fileName)
sfile.exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
if(!sfile)
throw std::runtime_error("Error: cannot open file '" + fileName.string() + "' for writing!");
throw std::runtime_error("Error: cannot open file '" + TextOperations::filesystemPathToUtf8(fileName) + "' for writing!");
sfile.write(reinterpret_cast<const char *>(saveData.data()), saveData.size());
}
+4 -4
View File
@@ -173,7 +173,7 @@ void emitClassFile(const boost::filesystem::path & outDir,
while(content.size() >= 2 && content[content.size() - 1] == '\n' && content[content.size() - 2] == '\n')
content.pop_back();
std::ofstream out((outDir / (typeName + ".md")).string());
std::ofstream out((outDir / (typeName + ".md")).c_str());
out << content;
}
@@ -181,7 +181,7 @@ void emitClassFile(const boost::filesystem::path & outDir,
void emitEnumFile(const boost::filesystem::path & outDir,
const FieldDocRegistrar::EnumGroupEntry & group)
{
std::ofstream out((outDir / (group.name + ".md")).string());
std::ofstream out((outDir / (group.name + ".md")).c_str());
out << "# " << group.name << "\n\n";
if(!group.description.empty())
@@ -200,7 +200,7 @@ void emitIndex(const boost::filesystem::path & outDir,
const std::vector<std::string> & classNames,
const std::vector<std::string> & enumNames)
{
std::ofstream out((outDir / "API.md").string());
std::ofstream out((outDir / "API.md").c_str());
out << "# Lua scripting API reference\n\n"
<< "Auto-generated from C++ host bindings via `vcmiserver --export-lua-docs`. Do not edit by hand.\n\n";
@@ -353,7 +353,7 @@ void exportLuaApiDocs(const boost::filesystem::path & outDir)
// Single LuaLS stub aggregating every type — kept as one file so modders can register
// it as a `Lua.workspace.library` path and get autocomplete across the whole API.
std::ofstream lua((outDir / "api.lua").string());
std::ofstream lua((outDir / "api.lua").c_str());
lua << "---@meta\n"
<< "-- Auto-generated Lua Language Server definitions for the VCMI scripting API.\n"
<< "-- Generated by `vcmiserver --export-lua-docs`. Do not edit by hand.\n\n";
+2 -2
View File
@@ -278,7 +278,7 @@ void CampaignEditor::on_actionOpen_triggered()
return;
auto title = tr("Open campaign");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = tr("All supported campaigns (*.vcmp *.h3c);;VCMI campaigns(*.vcmp);;HoMM3 campaigns(*.h3c)");
auto filenameSelect = EditorFileDialog::getOpenFileName(this, title, dir, filter);
@@ -339,7 +339,7 @@ void CampaignEditor::on_actionSave_as_triggered()
return;
auto title = tr("Save campaign");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = tr("VCMI campaigns (*.vcmp)");
QString contentUri;
@@ -403,7 +403,7 @@ void ScenarioProperties::on_pushButtonCreatureTypeNone_clicked()
void ScenarioProperties::on_pushButtonImport_clicked()
{
auto title = tr("Open map");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = tr("All supported maps (*.vmap *.h3m);;VCMI maps(*.vmap);;HoMM3 maps(*.h3m)");
auto filename = EditorFileDialog::getOpenFileName(this, title, dir, filter);
@@ -441,7 +441,7 @@ void ScenarioProperties::on_pushButtonExport_clicked()
bool isVmap = mapName.toLower().endsWith(".vmap");
auto title = tr("Save map");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = isVmap ? tr("VCMI maps (*.vmap);") : tr("HoMM3 maps (*.h3m);");
QString contentUri;
+2 -2
View File
@@ -111,7 +111,7 @@ ResourcePath addFilesystemAndGetResource(const QString & filenameSelect, EResTyp
{
QFileInfo fi(filenameSelect);
std::string fname = fi.fileName().toStdString();
std::string fdir = fi.dir().path().toStdString();
auto fdir = qstringToPath(fi.dir().path());
ResourcePath resId("MAPEDITOR/" + fname, type);
@@ -186,7 +186,7 @@ void Helper::saveCampaign(std::shared_ptr<CampaignState> campaignState, const QS
auto jsonCampaign = CampaignHandler::writeHeaderToJson(*campaignState, &translator);
auto io = std::make_shared<CDefaultIOApi>();
auto saver = std::make_shared<CZipSaver>(io, filename.toStdString());
auto saver = std::make_shared<CZipSaver>(io, qstringToPath(filename));
for(auto & scenario : campaignState->allScenarios())
{
EditorCallback cb(nullptr);
+9 -8
View File
@@ -22,6 +22,7 @@
#include <QTimer>
#include "../lib/VCMIDirs.h"
#include "../lib/texts/TextOperations.h"
#include "../lib/GameLibrary.h"
#include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/CConfigHandler.h"
@@ -167,7 +168,7 @@ void EditorMainWindow::loadUserSettings()
}
lastSavingDir = s.value(lastDirectorySetting).toString();
if(lastSavingDir.isEmpty())
lastSavingDir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
lastSavingDir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
}
void EditorMainWindow::saveUserSettings()
@@ -296,7 +297,7 @@ EditorMainWindow::EditorMainWindow(QWidget* parent) :
#endif
logConfig->configureDefault();
logGlobal->info("Starting map editor of '%s'", GameConstants::VCMI_PROJECT_NAME_VERSIONED);
logGlobal->info("The log file will be saved to %s", logPath);
logGlobal->info("The log file will be saved to %s", TextOperations::filesystemPathToUtf8(logPath));
//init
LIBRARY = new GameLibrary();
@@ -631,7 +632,7 @@ void EditorMainWindow::on_actionOpen_triggered()
return;
auto title = tr("Open map");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = tr("All supported maps (*.vmap *.h3m);;VCMI maps(*.vmap);;HoMM3 maps(*.h3m)");
auto filenameSelect = EditorFileDialog::getOpenFileName(this, title, dir, filter);
@@ -767,7 +768,7 @@ void EditorMainWindow::saveMap(bool force)
CMapService mapService;
try
{
mapService.saveMap(controller.getMapUniquePtr(), filename.toStdString());
mapService.saveMap(controller.getMapUniquePtr(), qstringToPath(filename));
}
catch(const std::exception & e)
{
@@ -1732,7 +1733,7 @@ void EditorMainWindow::on_actionTranslations_triggered()
void EditorMainWindow::on_actionh3m_converter_triggered()
{
auto mapFiles = QFileDialog::getOpenFileNames(this, tr("Select maps to convert"),
QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()),
pathToQString(VCMIDirs::get().userDataPath().make_preferred()),
tr("HoMM3 maps(*.h3m)"));
if(mapFiles.empty())
return;
@@ -1740,7 +1741,7 @@ void EditorMainWindow::on_actionh3m_converter_triggered()
#ifdef VCMI_ANDROID
QString contentUri;
QString saveDirectory = EditorFileDialog::getSaveFileName(this, tr("Choose directory to save converted maps"),
QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()) + "/Maps",
pathToQString(VCMIDirs::get().userDataPath().make_preferred()) + "/Maps",
tr("Directory"), contentUri);
if(saveDirectory.isEmpty())
return;
@@ -1760,7 +1761,7 @@ void EditorMainWindow::on_actionh3m_converter_triggered()
controller.getCallback()->setMap(map.get());
controller.repairMap(map.get());
QString outVmap = saveDirectory + '/' + QFileInfo(m).completeBaseName() + ".vmap";
mapService.saveMap(map, outVmap.toStdString());
mapService.saveMap(map, qstringToPath(outVmap));
}
QMessageBox::information(this, tr("Operation completed"), tr("Successfully converted %1 maps").arg(mapFiles.size()));
}
@@ -1772,7 +1773,7 @@ void EditorMainWindow::on_actionh3m_converter_triggered()
void EditorMainWindow::on_actionh3c_converter_triggered()
{
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto openTitle = tr("Select campaign to convert");
auto openFilter = tr("HoMM3 campaigns (*.h3c)");
@@ -14,6 +14,7 @@
#include "../../lib/VCMIDirs.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/texts/TextOperations.h"
#include "BitmapHandler.h"
#include "Animation.h"
@@ -39,7 +40,7 @@ void ResourceConverter::convertExtractedResourceFiles(ConversionOptions conversi
void ResourceConverter::doConvertPcxToPng(const boost::filesystem::path & sourceFolder, bool deleteOriginals)
{
logGlobal->info("Converting .pcx to .png from folder: %s ...\n", sourceFolder);
logGlobal->info("Converting .pcx to .png from folder: %s ...\n", TextOperations::filesystemPathToUtf8(sourceFolder));
for(const auto & directoryEntry : boost::filesystem::directory_iterator(sourceFolder))
{
@@ -49,13 +50,12 @@ void ResourceConverter::doConvertPcxToPng(const boost::filesystem::path & source
if(!boost::filesystem::is_regular_file(directoryEntry))
continue;
std::string fileStem = directoryEntry.path().stem().string();
std::string filenameLowerCase = boost::algorithm::to_lower_copy(filename.string());
std::string filenameLowerCase = boost::algorithm::to_lower_copy(TextOperations::filesystemPathToUtf8(filename));
if(boost::algorithm::to_lower_copy(filename.extension().string()) == ".pcx")
if(boost::algorithm::to_lower_copy(TextOperations::filesystemPathToUtf8(filename.extension())) == ".pcx")
{
auto img = BitmapHandler::loadBitmap(filenameLowerCase);
boost::filesystem::path pngFilePath = sourceFolder / (fileStem + ".png");
boost::filesystem::path pngFilePath = boost::filesystem::path(directoryEntry.path()).replace_extension(".png");
img.save(pathToQString(pngFilePath), "PNG");
if(deleteOriginals)
@@ -64,7 +64,7 @@ void ResourceConverter::doConvertPcxToPng(const boost::filesystem::path & source
}
catch(const std::exception& ex)
{
logGlobal->info(filename.string() + " " + ex.what() + "\n");
logGlobal->info(TextOperations::filesystemPathToUtf8(filename) + " " + ex.what() + "\n");
}
}
}
@@ -78,7 +78,7 @@ void ResourceConverter::splitDefFile(const std::string & fileName, const boost::
anim->exportBitmaps(pathToQString(sourceFolder));
if(deleteOriginals)
boost::filesystem::remove(sourceFolder / fileName);
boost::filesystem::remove(sourceFolder / TextOperations::Utf8TofilesystemPath(fileName));
}
else
logGlobal->error("Def File Split error! " + fileName);
@@ -86,7 +86,7 @@ void ResourceConverter::splitDefFile(const std::string & fileName, const boost::
void ResourceConverter::splitDefFiles(const std::vector<std::string> & defFileNames, const boost::filesystem::path & sourceFolder, bool deleteOriginals)
{
logGlobal->info("Splitting Def Files from folder: %s ...\n", sourceFolder);
logGlobal->info("Splitting Def Files from folder: %s ...\n", TextOperations::filesystemPathToUtf8(sourceFolder));
for(const auto & defFilename : defFileNames)
splitDefFile(defFilename, sourceFolder, deleteOriginals);
+1 -1
View File
@@ -781,7 +781,7 @@ void TemplateEditor::on_actionOpen_triggered()
return;
auto title = tr("Open template");
auto dir = QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string());
auto dir = pathToQString(VCMIDirs::get().userDataPath().make_preferred());
auto filter = tr("VCMI templates(*.json)");
auto filenameSelect = EditorFileDialog::getOpenFileName(this, title, dir, filter, /*externalOnly=*/true);
+3 -2
View File
@@ -27,6 +27,7 @@
#include "mapping/CMapService.h"
#include "modding/ModDescription.h"
#include "texts/CGeneralTextHandler.h"
#include "texts/TextOperations.h"
#include "../luascript/LuaModule.h"
#include <boost/program_options.hpp>
@@ -42,7 +43,7 @@ static void exportLuaApiDocs(const boost::filesystem::path & outPath)
scriptHandler->exportDocs(outPath);
logGlobal->info("Lua API documentation export complete");
logGlobal->info("Generated files can be found in " + outPath.string() + " directory");
logGlobal->info("Generated files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory");
}
static void generateTranslations(const std::string & modID)
@@ -221,7 +222,7 @@ static void generateTranslations(const std::string & modID)
mods->deletePreset("translation-export");
mods->deletePreset("translation-export-base");
logGlobal->info("Translation export complete");
logGlobal->info("Extracted files can be found in " + outPath.string() + " directory\n");
logGlobal->info("Extracted files can be found in " + TextOperations::filesystemPathToUtf8(outPath) + " directory\n");
}
+1 -1
View File
@@ -37,6 +37,6 @@ QString mapsPath()
QSettings getSettings(QString appName)
{
return QSettings(pathToQString(VCMIDirs::get().userConfigPath() / (appName.toStdString() + ".ini")), QSettings::IniFormat);
return QSettings(pathToQString(VCMIDirs::get().userConfigPath() / qstringToPath(appName + ".ini")), QSettings::IniFormat);
}
}