Skip to content

Commit

Permalink
Fix loading code-signed games on Windows with non-ascii paths.
Browse files Browse the repository at this point in the history
Use DroppedFile (renamed to NativeFile in love 12) instead of C file APIs. NativeFile properly handles unicode file paths on Windows.
  • Loading branch information
slime73 committed Feb 3, 2024
1 parent 0df51cf commit 5d11b09
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 81 deletions.
78 changes: 26 additions & 52 deletions src/modules/filesystem/physfs/PhysfsIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
* 3. This notice may not be removed or altered from any source distribution.
**/

#include <cassert>
#include <algorithm>

#include "PhysfsIo.h"
Expand All @@ -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.
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down
72 changes: 43 additions & 29 deletions src/modules/filesystem/physfs/PhysfsIo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -61,101 +61,115 @@ 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<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque));
}
};

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;
};
Expand Down

0 comments on commit 5d11b09

Please sign in to comment.