diff --git a/include/file.hpp b/include/file.hpp index aba7a84f..9a5e06bb 100644 --- a/include/file.hpp +++ b/include/file.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -85,17 +86,11 @@ public: : nullptr; } - char const *c_str(std::filesystem::path const &path) const { - // FIXME: This is a hack to prevent the path string from being destroyed until - // `.c_str(path)` is called again. It's necessary because just `return path.c_str()` - // fails on Windows, where paths use `wchar_t`. - static std::string path_string; - return std::visit(Visitor{[&path](std::filebuf const &) { - path_string = path.string(); - return path_string.c_str(); - }, + std::string string(std::filesystem::path const &path) const { + return std::visit(Visitor{[&path](std::filebuf const &) { return path.string(); }, [](std::streambuf const *buf) { - return buf == std::cin.rdbuf() ? "" : ""; + return std::string{buf == std::cin.rdbuf() + ? "" : ""}; }}, _file); } diff --git a/src/gfx/main.cpp b/src/gfx/main.cpp index 7a4298ed..b7aac36c 100644 --- a/src/gfx/main.cpp +++ b/src/gfx/main.cpp @@ -254,7 +254,7 @@ static std::vector readAtFile(std::filesystem::path const &path, std::vector &argPool) { File file; if (!file.open(path, std::ios_base::in)) { - fatal("Error reading @%s: %s", file.c_str(path), strerror(errno)); + fatal("Error reading @%s: %s", file.string(path).c_str(), strerror(errno)); } // We only filter out `EOF`, but calling `isblank()` on anything else is UB! diff --git a/src/gfx/process.cpp b/src/gfx/process.cpp index cbe5f60f..e6aac621 100644 --- a/src/gfx/process.cpp +++ b/src/gfx/process.cpp @@ -89,13 +89,13 @@ class Png { [[noreturn]] static void handleError(png_structp png, char const *msg) { Png *self = reinterpret_cast(png_get_error_ptr(png)); - fatal("Error reading input image (\"%s\"): %s", self->file.c_str(self->path), msg); + fatal("Error reading input image (\"%s\"): %s", self->string().c_str(), msg); } static void handleWarning(png_structp png, char const *msg) { Png *self = reinterpret_cast(png_get_error_ptr(png)); - warning("In input image (\"%s\"): %s", self->file.c_str(self->path), msg); + warning("In input image (\"%s\"): %s", self->string().c_str(), msg); } static void readData(png_structp png, png_bytep data, size_t length) { @@ -107,7 +107,7 @@ class Png { if (nbBytesRead != expectedLen) { fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more " "bytes after reading %lld)", - self->file.c_str(self->path), length - nbBytesRead, + self->string().c_str(), length - nbBytesRead, self->file->pubseekoff(0, std::ios_base::cur)); } } @@ -129,6 +129,8 @@ public: Rgba const &pixel(uint32_t x, uint32_t y) const { return pixels[y * width + x]; } + std::string string() const { return file.string(path); } + bool isSuitableForGrayscale() const { // Check that all of the grays don't fall into the same "bin" if (colors.size() > options.maxOpaqueColors()) { // Apply the Pigeonhole Principle @@ -172,7 +174,8 @@ public: */ explicit Png(std::filesystem::path const &filePath) : path(filePath), colors() { if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) { - fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), strerror(errno)); + fatal("Failed to open input image (\"%s\"): %s", file.string(path).c_str(), + strerror(errno)); } options.verbosePrint(Options::VERB_LOG_ACT, "Opened input file\n"); @@ -182,7 +185,7 @@ public: if (file->sgetn(reinterpret_cast(pngHeader.data()), pngHeader.size()) != static_cast(pngHeader.size()) // Not enough bytes? || png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) { - fatal("Input file (\"%s\") is not a PNG image!", file.c_str(path)); + fatal("Input file (\"%s\") is not a PNG image!", file.string(path).c_str()); } options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n"); @@ -641,7 +644,7 @@ static void outputPalettes(std::vector const &palettes) { if (options.palettes.has_value()) { File output; if (!output.open(*options.palettes, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to open \"%s\": %s", output.c_str(*options.palettes), + fatal("Failed to open \"%s\": %s", output.string(*options.palettes).c_str(), strerror(errno)); } @@ -772,7 +775,8 @@ static void outputTileData(Png const &png, DefaultInitVec const &a DefaultInitVec const &mappings) { File output; if (!output.open(*options.output, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to open \"%s\": %s", output.c_str(*options.output), strerror(errno)); + fatal("Failed to open \"%s\": %s", output.string(*options.output).c_str(), + strerror(errno)); } uint16_t widthTiles = options.inputSlice.width ? options.inputSlice.width : png.getWidth() / 8; @@ -809,7 +813,7 @@ static void outputMaps(DefaultInitVec const &attrmap, if (path.has_value()) { file.emplace(); if (!file->open(*path, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to open \"%s\": %s", file->c_str(*path), + fatal("Failed to open \"%s\": %s", file->string(*path).c_str(), strerror(errno)); } } @@ -912,7 +916,8 @@ static UniqueTiles dedupTiles(Png const &png, DefaultInitVec &attr static void outputTileData(UniqueTiles const &tiles) { File output; if (!output.open(*options.output, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to create \"%s\": %s", output.c_str(*options.output), strerror(errno)); + fatal("Failed to create \"%s\": %s", output.string(*options.output).c_str(), + strerror(errno)); } uint16_t tileID = 0; @@ -927,7 +932,8 @@ static void outputTileData(UniqueTiles const &tiles) { static void outputTilemap(DefaultInitVec const &attrmap) { File output; if (!output.open(*options.tilemap, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to create \"%s\": %s", output.c_str(*options.tilemap), strerror(errno)); + fatal("Failed to create \"%s\": %s", output.string(*options.tilemap).c_str(), + strerror(errno)); } for (AttrmapEntry const &entry : attrmap) { @@ -939,7 +945,8 @@ static void outputAttrmap(DefaultInitVec const &attrmap, DefaultInitVec const &mappings) { File output; if (!output.open(*options.attrmap, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to create \"%s\": %s", output.c_str(*options.attrmap), strerror(errno)); + fatal("Failed to create \"%s\": %s", output.string(*options.attrmap).c_str(), + strerror(errno)); } for (AttrmapEntry const &entry : attrmap) { @@ -954,7 +961,8 @@ static void outputPalmap(DefaultInitVec const &attrmap, DefaultInitVec const &mappings) { File output; if (!output.open(*options.palmap, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to create \"%s\": %s", output.c_str(*options.palmap), strerror(errno)); + fatal("Failed to create \"%s\": %s", output.string(*options.palmap).c_str(), + strerror(errno)); } for (AttrmapEntry const &entry : attrmap) { diff --git a/src/gfx/reverse.cpp b/src/gfx/reverse.cpp index f6f317a2..1dcae1dc 100644 --- a/src/gfx/reverse.cpp +++ b/src/gfx/reverse.cpp @@ -25,7 +25,7 @@ static DefaultInitVec readInto(std::filesystem::path path) { File file; if (!file.open(path, std::ios::in | std::ios::binary)) { - fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno)); + fatal("Failed to open \"%s\": %s", file.string(path).c_str(), strerror(errno)); } DefaultInitVec data(128 * 16); // Begin with some room pre-allocated @@ -144,7 +144,8 @@ void reverse() { if (options.palettes.has_value()) { File file; if (!file.open(*options.palettes, std::ios::in | std::ios::binary)) { - fatal("Failed to open \"%s\": %s", file.c_str(*options.palettes), strerror(errno)); + fatal("Failed to open \"%s\": %s", file.string(*options.palettes).c_str(), + strerror(errno)); } palettes.clear(); @@ -231,12 +232,13 @@ void reverse() { options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n"); File pngFile; if (!pngFile.open(*options.input, std::ios::out | std::ios::binary)) { - fatal("Failed to create \"%s\": %s", pngFile.c_str(*options.input), strerror(errno)); + fatal("Failed to create \"%s\": %s", pngFile.string(*options.input).c_str(), + strerror(errno)); } png_structp png = png_create_write_struct( PNG_LIBPNG_VER_STRING, - const_cast(static_cast(pngFile.c_str(*options.input))), pngError, - pngWarning); + const_cast(static_cast(pngFile.string(*options.input).c_str())), + pngError, pngWarning); if (!png) { fatal("Couldn't create PNG write struct: %s", strerror(errno)); }