From 5d11b095e87b9f8ac52611dfc7cf76d908f363e9 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 3 Feb 2024 12:06:27 -0400 Subject: [PATCH] Fix loading code-signed games on Windows with non-ascii paths. Use DroppedFile (renamed to NativeFile in love 12) instead of C file APIs. NativeFile properly handles unicode file paths on Windows. --- src/modules/filesystem/physfs/PhysfsIo.cpp | 78 ++++++++-------------- src/modules/filesystem/physfs/PhysfsIo.h | 72 ++++++++++++-------- 2 files changed, 69 insertions(+), 81 deletions(-) diff --git a/src/modules/filesystem/physfs/PhysfsIo.cpp b/src/modules/filesystem/physfs/PhysfsIo.cpp index cdcea8dd2..adb392393 100644 --- a/src/modules/filesystem/physfs/PhysfsIo.cpp +++ b/src/modules/filesystem/physfs/PhysfsIo.cpp @@ -18,7 +18,6 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include #include #include "PhysfsIo.h" @@ -32,14 +31,15 @@ namespace physfs bool StripSuffixIo::determineStrippedLength() { - if (!file) { + if (!file) return false; - } - const int64_t fullSize = fullLength(); - int64_t chunkSize = std::min(fullSize, (int64_t)8192); + + const int64 fullSize = file->getSize(); + + int64 chunkSize = std::min(fullSize, (int64) 8192); std::string buffer; buffer.reserve(chunkSize); - int64_t i = fullSize - chunkSize; + int64 i = fullSize - chunkSize; // I don't think we really need to go through the whole file. The main known use // case for this functionality is to skip windows codesign signatures, which are // from what I have seen ~12KB or so, but trying is better than just failing. @@ -64,7 +64,7 @@ bool StripSuffixIo::determineStrippedLength() } if (i == 0) break; - i = std::max((int64_t)0, i - chunkSize); + i = std::max((int64)0, i - chunkSize); } if (i > 0) @@ -75,7 +75,7 @@ bool StripSuffixIo::determineStrippedLength() // The comment length (u16) is located 20 bytes from the start of the EOCD record if (seek(i + 20) == 0) return false; - uint8_t buffer[2]; + uint8 buffer[2]; const auto n = read(buffer, 2); if (n <= 0) return false; @@ -96,17 +96,17 @@ bool StripSuffixIo::determineStrippedLength() return true; } -int64_t StripSuffixIo::read(void* buf, uint64_t len) +int64 StripSuffixIo::read(void *buf, uint64 len) { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return -1; } - const auto ret = std::fread(buf, 1, len, file); - if (ret == 0) + int64 r = file->read(buf, (int64) len); + if (r == 0) { - if (std::feof(file)) + if (file->isEOF()) { PHYSFS_setErrorCode(PHYSFS_ERR_OK); return 0; @@ -117,85 +117,59 @@ int64_t StripSuffixIo::read(void* buf, uint64_t len) return -1; } } - else if (ret < len && std::ferror(file)) - { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } PHYSFS_setErrorCode(PHYSFS_ERR_OK); - return ret; + return r; } -int64_t StripSuffixIo::write(const void* /*buf*/, uint64_t /*len*/) +int64 StripSuffixIo::write(const void */*buf*/, uint64 /*len*/) { PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY); return -1; } -int64_t StripSuffixIo::seek(uint64_t offset) +int64 StripSuffixIo::seek(uint64 offset) { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return 0; } - const auto ret = std::fseek(file, offset, SEEK_SET); - PHYSFS_setErrorCode(ret != 0 ? PHYSFS_ERR_OS_ERROR : PHYSFS_ERR_OK); - return ret == 0 ? 1 : 0; + bool success = file->seek(offset); + PHYSFS_setErrorCode(success ? PHYSFS_ERR_OK : PHYSFS_ERR_OS_ERROR); + return success ? 1 : 0; } -int64_t StripSuffixIo::tell() +int64 StripSuffixIo::tell() { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return -1; } - return std::ftell(file); + return file->tell(); } -int64_t StripSuffixIo::length() +int64 StripSuffixIo::length() { return strippedLength_; } -int64_t StripSuffixIo::flush() +int64 StripSuffixIo::flush() { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return 0; } - return std::fflush(file) == 0 ? 1 : 0; -} - -int64_t StripSuffixIo::fullLength() -{ - assert(file); - const auto cur = std::ftell(file); - if (cur == -1) + try { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } - if (std::fseek(file, 0, SEEK_END) != 0) - { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; + return file->flush() ? 1 : 0; } - const auto len = std::ftell(file); - if (len == -1) + catch (love::Exception &) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } - if (std::fseek(file, cur, SEEK_SET) != 0) - { - // We do have the length now, but something is wrong, so we return an error anyways - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; + return 0; } - return len; } } // physfs diff --git a/src/modules/filesystem/physfs/PhysfsIo.h b/src/modules/filesystem/physfs/PhysfsIo.h index 35b92cc6c..423d671e5 100644 --- a/src/modules/filesystem/physfs/PhysfsIo.h +++ b/src/modules/filesystem/physfs/PhysfsIo.h @@ -21,11 +21,11 @@ #ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H #define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H -#include -#include -#include - #include "libraries/physfs/physfs.h" +#include "common/int.h" +#include "filesystem/DroppedFile.h" + +#include namespace love { @@ -61,54 +61,54 @@ struct PhysfsIo : PHYSFS_Io private: // Returns: number of bytes read, 0 on EOF, -1 on failure - static PHYSFS_sint64 staticRead(struct PHYSFS_Io* io, void* buf, PHYSFS_uint64 len) + static PHYSFS_sint64 staticRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) { return derived(io)->read(buf, len); } // Returns: number of bytes written, -1 on failure - static PHYSFS_sint64 staticWrite(struct PHYSFS_Io* io, const void* buf, PHYSFS_uint64 len) + static PHYSFS_sint64 staticWrite(struct PHYSFS_Io *io, const void *buf, PHYSFS_uint64 len) { return derived(io)->write(buf, len); } // Returns: non-zero on success, zero on error - static int staticSeek(struct PHYSFS_Io* io, PHYSFS_uint64 offset) + static int staticSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset) { return derived(io)->seek(offset); } // Returns: current offset from start, -1 on error - static PHYSFS_sint64 staticTell(struct PHYSFS_Io* io) + static PHYSFS_sint64 staticTell(struct PHYSFS_Io *io) { return derived(io)->tell(); } // Returns: total size in bytes, -1 on error - static PHYSFS_sint64 staticLength(struct PHYSFS_Io* io) + static PHYSFS_sint64 staticLength(struct PHYSFS_Io *io) { return derived(io)->length(); } - static struct PHYSFS_Io* staticDuplicate(struct PHYSFS_Io* io) + static struct PHYSFS_Io *staticDuplicate(struct PHYSFS_Io *io) { // Just use copy constructor return new Derived(*derived(io)); } // Returns: non-zero on success, zero on error - static int staticFlush(struct PHYSFS_Io* io) + static int staticFlush(struct PHYSFS_Io *io) { return derived(io)->flush(); } - static void staticDestroy(struct PHYSFS_Io* io) + static void staticDestroy(struct PHYSFS_Io *io) { // Just use destructor delete derived(io); } - static Derived* derived(PHYSFS_Io* io) + static Derived* derived(PHYSFS_Io *io) { return static_cast(reinterpret_cast(io->opaque)); } @@ -116,46 +116,60 @@ struct PhysfsIo : PHYSFS_Io struct StripSuffixIo : public PhysfsIo { - static const uint32_t version = 0; + static const uint32 version = 0; std::string filename; - FILE* file = nullptr; + DroppedFile *file = nullptr; // The constructor is private in favor of this function to prevent stack allocation // because Physfs will take ownership of this object and call destroy on it later. - static StripSuffixIo* create(std::string f) { return new StripSuffixIo(f); } + static StripSuffixIo *create(const std::string &f) { return new StripSuffixIo(f); } virtual ~StripSuffixIo() { if (file) { - std::fclose(file); + file->release(); } } - StripSuffixIo(const StripSuffixIo& other) + StripSuffixIo(const StripSuffixIo &other) : StripSuffixIo(other.filename) { } bool determineStrippedLength(); - int64_t read(void* buf, uint64_t len); - int64_t write(const void* buf, uint64_t len); - int64_t seek(uint64_t offset); - int64_t tell(); - int64_t length(); - int64_t flush(); + int64 read(void *buf, uint64 len); + int64 write(const void *buf, uint64 len); + int64 seek(uint64 offset); + int64 tell(); + int64 length(); + int64 flush(); private: - StripSuffixIo(std::string f) - : filename(std::move(f)) - , file(std::fopen(filename.c_str(), "rb")) + StripSuffixIo(const std::string &f) + : filename(f) + , file(new DroppedFile(f)) { - } + bool success = false; - int64_t fullLength(); + try + { + success = file->open(File::MODE_READ); + } + catch (love::Exception &) + { + success = false; + } + + if (!success) + { + file->release(); + file = nullptr; + } + } int64_t strippedLength_ = -1; };