Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert filesystem::path into char* on windows

Tags:

c++

c++17

The C++17 filesystem is based on boost.filesystem.

I am using it on Windows with VS2017 right now.

#include <filesystem>
namespace fs = std::experimental::filesystem;

I iterate over a directory

for (auto& p: fs::directory_iterator("media"))

I want to pass the paths to a function that takes filepaths as const char *

I found a similar question about the boost filesystem here. A core difference is that the path in C++17 is based on a value_type. where

value_type: character type used by the native encoding of the filesystem: char on POSIX, wchar_t on Windows

So what I get is a const wchar_t * string.

The following "works" for me:

    char file[2000];
    wcstombs(file, p.path().c_str(), 2000);
    auto image = SDL_LoadBMP(file);

I am looking for a different version since this implementation is all sorts of messy (decaying array to pointer and _CRT_SECURE_NO_WARNINGS).

I am looking for a prettier version that can go straight from path to const char * using the new C++17 filesystem on windows.

Here is my SDL2 project that I used to explore this with.

#define _CRT_SECURE_NO_WARNINGS 1
#include <SDL.h>
#include <vector>
#include <filesystem>
namespace fs = std::experimental::filesystem;

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);
    auto window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 400, SDL_WINDOW_SHOWN);
    auto scrrenSurface = SDL_GetWindowSurface(window);

    auto images = std::vector<SDL_Surface*>();

    for (auto& p: fs::directory_iterator("media"))
    {
        char file[2000];
        wcstombs(file, p.path().c_str(), 2000);
        auto image = SDL_LoadBMP(file);
        images.push_back(image);
    }

    for (auto&image : images)
    {
        SDL_BlitSurface(image, NULL, scrrenSurface, NULL);
        SDL_UpdateWindowSurface(window);
        SDL_Delay(2000);
    }

    for (auto&image : images)
        SDL_FreeSurface(image);

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

EDIT: In the comment section there is a simmilar question linked so-question That questions is a different manifestation of the same core issue which is converting path to a format that can be consumed by another method. I would argue against deleting this question because of the way both are found with different searches.

like image 871
Johannes Avatar asked Jan 09 '19 11:01

Johannes


1 Answers

You can use the *string() and generic_*string() member functions of the std::filesystem::path object to convert the path into either a native or a generic (i.e., POSIX-style) string. For example:

SDL_LoadBMP(p.path().string().c_str());

Note that these methods return an std::basic_string<T> value. So one must make sure that, e.g., a pointer obtained from calling .c_str() directly on the return value—like in the example above—does not outlive the string it points to…

like image 91
Michael Kenzel Avatar answered Oct 04 '22 06:10

Michael Kenzel