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.
This commit is contained in:
Sasha Szpakowski
2024-02-03 12:06:27 -04:00
parent 0df51cf743
commit 5d11b095e8
2 changed files with 71 additions and 83 deletions
+28 -54
View File
@@ -18,7 +18,6 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
#include <cassert>
#include <algorithm>
#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
{
return file->flush() ? 1 : 0;
}
catch (love::Exception &)
{
PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
return -1;
return 0;
}
if (std::fseek(file, 0, SEEK_END) != 0)
{
PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
return -1;
}
const auto len = std::ftell(file);
if (len == -1)
{
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 len;
}
} // physfs
+43 -29
View File
@@ -21,11 +21,11 @@
#ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
#define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
#include <cstdint>
#include <cstdio>
#include <string>
#include "libraries/physfs/physfs.h"
#include "common/int.h"
#include "filesystem/DroppedFile.h"
#include <string>
namespace love
{
@@ -61,54 +61,54 @@ protected:
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<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque));
}
@@ -116,46 +116,60 @@ private:
struct StripSuffixIo : public PhysfsIo<StripSuffixIo>
{
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;
};