Use std::filesystem::path and u8string to ensure UTF-8 is used for paths on Windows

This commit is contained in:
Yousef Khadadeh 2025-11-21 08:35:47 +03:00
parent 5f4bc6e1cb
commit 6839e529c1
10 changed files with 59 additions and 60 deletions

View file

@ -426,14 +426,14 @@ void DrawingProgram::force_rebuild_cache() {
void DrawingProgram::drag_drop_update() {
if(controls.cursorHoveringOverCanvas) {
for(auto& droppedItem : world.main.input.droppedItems) {
if(droppedItem.isFile && std::filesystem::is_regular_file(droppedItem.droppedData)) {
if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) {
#ifdef __EMSCRIPTEN_
add_file_to_canvas_by_path(droppedItem.droppedData, world.main.input.mouse.pos, true);
add_file_to_canvas_by_path(droppedItem.dataPath.value(), world.main.input.mouse.pos, true);
#else
add_file_to_canvas_by_path(droppedItem.droppedData, droppedItem.pos, true);
add_file_to_canvas_by_path(droppedItem.dataPath.value(), droppedItem.pos, true);
#endif
}
else if(!droppedItem.isFile && is_valid_http_url(droppedItem.droppedData)) {
else if(!droppedItem.dataText.has_value() && is_valid_http_url(droppedItem.dataText.value())) {
auto img(std::make_shared<DrawImage>());
img->coords = world.drawData.cam.c;
Vector2f imDim = Vector2f{100.0f, 100.0f};
@ -445,7 +445,7 @@ void DrawingProgram::drag_drop_update() {
auto objAdd = components.client_insert(placement, img);
img->client_send_place(*this);
add_undo_place_component(objAdd);
droppedDownloadingFiles.emplace_back(objAdd, world.main.window.size.cast<float>(), FileDownloader::download_data_from_url(droppedItem.droppedData));
droppedDownloadingFiles.emplace_back(objAdd, world.main.window.size.cast<float>(), FileDownloader::download_data_from_url(droppedItem.dataText.value()));
}
}
}
@ -492,7 +492,7 @@ void DrawingProgram::update_downloading_dropped_files() {
});
}
void DrawingProgram::add_file_to_canvas_by_path(const std::string& filePath, Vector2f dropPos, bool addInSameThread) {
void DrawingProgram::add_file_to_canvas_by_path(const std::filesystem::path& filePath, Vector2f dropPos, bool addInSameThread) {
if(addInSameThread)
add_file_to_canvas_by_path_execute(filePath, dropPos);
else if(!addFileInNextFrame) {
@ -501,23 +501,25 @@ void DrawingProgram::add_file_to_canvas_by_path(const std::string& filePath, Vec
}
}
void DrawingProgram::add_file_to_canvas_by_path_execute(const std::string& filePath, Vector2f dropPos) {
void DrawingProgram::add_file_to_canvas_by_path_execute(const std::filesystem::path& filePath, Vector2f dropPos) {
ServerClientID imageID = world.rMan.add_resource_file(filePath);
ResourceDisplay* display = world.rMan.get_display_data(imageID);
Vector2f imTrueDim = display->get_dimensions();
auto img(std::make_shared<DrawImage>());
img->coords = world.drawData.cam.c;
float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y());
float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y());
Vector2f imDim = Vector2f{world.main.window.size.x() * imWidth, world.main.window.size.x() * imHeight} * display->get_dimension_scale();
img->d.p1 = dropPos - imDim;
img->d.p2 = dropPos + imDim;
img->d.imageID = imageID;
img->commit_update(*this);
uint64_t placement = components.client_list().size();
auto objAdd = components.client_insert(placement, img);
img->client_send_place(*this);
add_undo_place_component(objAdd);
if(imageID != ServerClientID{0, 0}) {
ResourceDisplay* display = world.rMan.get_display_data(imageID);
Vector2f imTrueDim = display->get_dimensions();
auto img(std::make_shared<DrawImage>());
img->coords = world.drawData.cam.c;
float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y());
float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y());
Vector2f imDim = Vector2f{world.main.window.size.x() * imWidth, world.main.window.size.x() * imHeight} * display->get_dimension_scale();
img->d.p1 = dropPos - imDim;
img->d.p2 = dropPos + imDim;
img->d.imageID = imageID;
img->commit_update(*this);
uint64_t placement = components.client_list().size();
auto objAdd = components.client_insert(placement, img);
img->client_send_place(*this);
add_undo_place_component(objAdd);
}
}
void DrawingProgram::add_file_to_canvas_by_data(const std::string& fileName, std::string_view fileBuffer, Vector2f dropPos) {

View file

@ -41,7 +41,7 @@ class DrawingProgram {
bool prevent_undo_or_redo();
void add_file_to_canvas_by_path(const std::string& filePath, Vector2f dropPos, bool addInSameThread);
void add_file_to_canvas_by_path(const std::filesystem::path& filePath, Vector2f dropPos, bool addInSameThread);
void add_file_to_canvas_by_data(const std::string& fileName, std::string_view fileBuffer, Vector2f dropPos);
void parallel_loop_all_components(std::function<void(const std::shared_ptr<CollabList<std::shared_ptr<DrawComponent>, ServerClientID>::ObjectInfo>&)> func);
@ -82,7 +82,7 @@ class DrawingProgram {
std::atomic<bool> addFileInNextFrame = false;
std::pair<std::string, Vector2f> addFileInfo;
void add_file_to_canvas_by_path_execute(const std::string& filePath, Vector2f dropPos);
void add_file_to_canvas_by_path_execute(const std::filesystem::path& filePath, Vector2f dropPos);
void drag_drop_update();

View file

@ -113,9 +113,9 @@ struct InputManager {
} text;
struct DroppedItem {
bool isFile;
Vector2f pos;
std::string droppedData;
std::optional<std::string> dataText;
std::optional<std::filesystem::path> dataPath;
};
#ifdef __APPLE__

View file

@ -73,12 +73,12 @@ void MainProgram::update() {
lastFrameTime = std::chrono::steady_clock::now();
std::erase_if(input.droppedItems, [&](auto& droppedItem) {
if(droppedItem.isFile && std::filesystem::is_regular_file(droppedItem.droppedData)) {
std::filesystem::path droppedFilePath(droppedItem.droppedData);
if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) {
const std::filesystem::path& droppedFilePath = droppedItem.dataPath.value();
if(droppedFilePath.has_extension() && droppedFilePath.extension().string() == std::string("." + World::FILE_EXTENSION)) {
new_tab({
.conType = World::CONNECTIONTYPE_LOCAL,
.fileSource = droppedFilePath.string()
.filePathSource = droppedFilePath
}, true);
return true;
}
@ -152,7 +152,7 @@ void MainProgram::new_tab_open() {
newWorld = std::make_unique<World>(*this, newTabToOpenInfo);
}
catch(const std::runtime_error& e) {
Logger::get().log("WORLDFATAL", "Failed to open canvas: " + std::string(newTabToOpenInfo.fileSource) + " with error: " + e.what());
Logger::get().log("WORLDFATAL", "Failed to open canvas: " + (newTabToOpenInfo.filePathSource.has_value() ? newTabToOpenInfo.filePathSource.value().string() : "NO PATH") + " with error: " + e.what());
return;
}
worlds.emplace_back(std::move(newWorld));

View file

@ -65,11 +65,11 @@ void ResourceManager::update() {
v->update(world);
}
ServerClientID ResourceManager::add_resource_file(std::string_view fileName) {
ServerClientID ResourceManager::add_resource_file(const std::filesystem::path& filePath) {
// https://nullptr.org/cpp-read-file-into-string/
std::ifstream file(fileName.data(), std::ios::in | std::ios::binary | std::ios::ate);
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
if(!file.is_open()) {
Logger::get().log("INFO", "[ResourceManager::add_resource_file] Could not open file " + std::string(fileName));
Logger::get().log("INFO", "[ResourceManager::add_resource_file] Could not open file " + std::string(filePath));
return {0, 0};
}
@ -78,7 +78,7 @@ ServerClientID ResourceManager::add_resource_file(std::string_view fileName) {
auto tellgResult = file.tellg();
if(tellgResult == -1) {
Logger::get().log("INFO", "[ResourceManager::add_resource_file] tellg failed for file " + std::string(fileName));
Logger::get().log("INFO", "[ResourceManager::add_resource_file] tellg failed for file " + std::string(filePath));
return {0, 0};
}
@ -88,7 +88,7 @@ ServerClientID ResourceManager::add_resource_file(std::string_view fileName) {
ResourceData resource;
resource.data = std::make_shared<std::string>();
resource.name = std::filesystem::path(fileName).filename().string();
resource.name = std::filesystem::path(filePath).filename().string();
std::string& toPlaceIn = *resource.data;
toPlaceIn.resize(resourcesize);
@ -97,7 +97,7 @@ ServerClientID ResourceManager::add_resource_file(std::string_view fileName) {
file.close();
Logger::get().log("INFO", "[ResourceManager::add_resource_file] Successfully read file " + std::string(fileName));
Logger::get().log("INFO", "[ResourceManager::add_resource_file] Successfully read file " + filePath.string());
return add_resource(resource);
}

View file

@ -39,7 +39,7 @@ class ResourceManager {
void update();
void copy_resource_set_to_map(const std::unordered_set<ServerClientID>& resourceSet, std::unordered_map<ServerClientID, ResourceData>& resourceMap) const;
void init_client_callbacks();
ServerClientID add_resource_file(std::string_view fileName);
ServerClientID add_resource_file(const std::filesystem::path& filePath);
ServerClientID add_resource(const ResourceData& resource);
ResourceDisplay* get_display_data(const ServerClientID& fileID);
std::optional<ResourceData> get_resource(const ServerClientID& id) const;

View file

@ -187,7 +187,7 @@ void Toolbar::color_selector_right(Vector4f* color) {
}
void Toolbar::load_licenses() {
std::filesystem::path third_party_license_path = "data/third_party_licenses";
std::filesystem::path third_party_license_path("data/third_party_licenses");
for(const auto& entry : std::filesystem::directory_iterator(third_party_license_path)) {
if(entry.is_regular_file())
thirdPartyLicenses.emplace_back(entry.path().filename().string(), read_file_to_string(entry.path()));
@ -1269,7 +1269,7 @@ void Toolbar::open_world_file(int conType, const std::string& netSource, const s
UploadData* uD = (UploadData*)callbackData;
uD->main->new_tab({
.conType = (World::ConnectionType)uD->cT,
.fileSource = fileName,
.filePathSource = std::filesystem::path(fileName),
.netSource = uD->nS,
.serverLocalID = uD->sLID,
.fileDataBuffer = buffer
@ -1280,7 +1280,7 @@ void Toolbar::open_world_file(int conType, const std::string& netSource, const s
open_file_selector("Open", {{"Any File", "*"}, {"InfiniPaint Canvas", World::FILE_EXTENSION}}, [&, conType = conType, netSource = netSource, serverLocalID2 = serverLocalID2](const std::filesystem::path& p, const auto& e) {
main.new_tab({
.conType = (World::ConnectionType)conType,
.fileSource = p.string(),
.filePathSource = p,
.netSource = netSource,
.serverLocalID = serverLocalID2
});
@ -1334,7 +1334,6 @@ void Toolbar::options_menu() {
else {
main.new_tab({
.conType = World::CONNECTIONTYPE_CLIENT,
.fileSource = "",
.netSource = serverToConnectTo
}, true);
optionsMenuOpen = false;

View file

@ -52,8 +52,8 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo):
break;
}
case CONNECTIONTYPE_LOCAL: {
if(!worldInfo.fileSource.empty())
load_from_file(worldInfo.fileSource, worldInfo.fileDataBuffer);
if(worldInfo.filePathSource.has_value())
load_from_file(worldInfo.filePathSource.value(), worldInfo.fileDataBuffer);
set_name(name);
break;
}
@ -270,9 +270,9 @@ void World::start_hosting(const std::string& initNetSource, const std::string& s
clientStillConnecting = true;
}
void World::save_to_file(const std::filesystem::path& fileName) {
void World::save_to_file(const std::filesystem::path& filePathToSaveAt) {
try {
filePath = force_extension_on_path(fileName, FILE_EXTENSION);
filePath = force_extension_on_path(filePathToSaveAt, FILE_EXTENSION);
std::stringstream f;
f.write(VersionConstants::CURRENT_SAVEFILE_HEADER.c_str(), VersionConstants::SAVEFILE_HEADER_LEN);
@ -312,13 +312,13 @@ void World::save_to_file(const std::filesystem::path& fileName) {
}
}
void World::load_from_file(const std::filesystem::path& fileName, std::string_view buffer) {
filePath = force_extension_on_path(fileName, FILE_EXTENSION);
void World::load_from_file(const std::filesystem::path& filePathToLoadFrom, std::string_view buffer) {
filePath = force_extension_on_path(filePathToLoadFrom, FILE_EXTENSION);
std::string byteDataFromFile;
if(buffer.empty()) {
byteDataFromFile = read_file_to_string(fileName);
byteDataFromFile = read_file_to_string(filePath);
buffer = byteDataFromFile;
}

View file

@ -26,7 +26,7 @@ class World {
struct OpenWorldInfo {
ConnectionType conType;
std::string fileSource;
std::optional<std::filesystem::path> filePathSource;
std::string netSource;
std::string serverLocalID;
std::string_view fileDataBuffer;
@ -75,8 +75,8 @@ class World {
ConnectionType conType;
bool clientStillConnecting = false;
void save_to_file(const std::filesystem::path& fileName);
void load_from_file(const std::filesystem::path& fileName, std::string_view buffer);
void save_to_file(const std::filesystem::path& filePathToSaveAt);
void load_from_file(const std::filesystem::path& filePathToLoadFrom, std::string_view buffer);
void undo_with_checks();
void redo_with_checks();

View file

@ -385,7 +385,7 @@ void init_logs(MainStruct& mS) {
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
std::vector<std::filesystem::path> listOfFilesToOpenFromCommand;
for(int i = 1; i < argc; i++)
listOfFilesToOpenFromCommand.emplace_back(std::filesystem::canonical(std::filesystem::path(argv[i])));
listOfFilesToOpenFromCommand.emplace_back(std::filesystem::canonical(std::filesystem::path(std::u8string_view(reinterpret_cast<char8_t*>(argv[i])))));
switch_cwd();
UErrorCode uerr = U_ZERO_ERROR;
@ -530,10 +530,10 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
}, true);
}
else {
for(auto& f : listOfFilesToOpenFromCommand) {
for(std::filesystem::path& f : listOfFilesToOpenFromCommand) {
mS.m->new_tab({
.conType = World::CONNECTIONTYPE_LOCAL,
.fileSource = f.string()
.filePathSource = f
}, true);
}
}
@ -702,17 +702,15 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
case SDL_EVENT_DROP_FILE:
mS.m->window.scale = SDL_GetWindowPixelDensity(mS.window);
mS.m->input.droppedItems.emplace_back(InputManager::DroppedItem{
true,
Vector2f{event->drop.x, event->drop.y} * mS.m->window.scale,
event->drop.data
.pos = Vector2f{event->drop.x, event->drop.y} * mS.m->window.scale,
.dataPath = std::u8string_view(reinterpret_cast<const char8_t*>(event->drop.data))
});
break;
case SDL_EVENT_DROP_TEXT:
mS.m->window.scale = SDL_GetWindowPixelDensity(mS.window);
mS.m->input.droppedItems.emplace_back(InputManager::DroppedItem{
false,
Vector2f{event->drop.x, event->drop.y} * mS.m->window.scale,
event->drop.data
.pos = Vector2f{event->drop.x, event->drop.y} * mS.m->window.scale,
.dataText = event->drop.data
});
break;
case SDL_EVENT_PEN_PROXIMITY_IN: {