Browse Source

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.
Sasha Szpakowski 1 year ago
parent
commit
5d11b095e8
2 changed files with 69 additions and 81 deletions
  1. 26 52
      src/modules/filesystem/physfs/PhysfsIo.cpp
  2. 43 29
      src/modules/filesystem/physfs/PhysfsIo.h

+ 26 - 52
src/modules/filesystem/physfs/PhysfsIo.cpp

@@ -18,7 +18,6 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
-#include <cassert>
 #include <algorithm>
 #include <algorithm>
 
 
 #include "PhysfsIo.h"
 #include "PhysfsIo.h"
@@ -32,14 +31,15 @@ namespace physfs
 
 
 bool StripSuffixIo::determineStrippedLength()
 bool StripSuffixIo::determineStrippedLength()
 {
 {
-	if (!file) {
+	if (!file)
 		return false;
 		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;
 	std::string buffer;
 	buffer.reserve(chunkSize);
 	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
 	// 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
 	// 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.
 	// 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)
 		if (i == 0)
 			break;
 			break;
-		i = std::max((int64_t)0, i - chunkSize);
+		i = std::max((int64)0, i - chunkSize);
 	}
 	}
 
 
 	if (i > 0)
 	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
 		// The comment length (u16) is located 20 bytes from the start of the EOCD record
 		if (seek(i + 20) == 0)
 		if (seek(i + 20) == 0)
 			return false;
 			return false;
-		uint8_t buffer[2];
+		uint8 buffer[2];
 		const auto n = read(buffer, 2);
 		const auto n = read(buffer, 2);
 		if (n <= 0)
 		if (n <= 0)
 			return false;
 			return false;
@@ -96,17 +96,17 @@ bool StripSuffixIo::determineStrippedLength()
 	return true;
 	return true;
 }
 }
 
 
-int64_t StripSuffixIo::read(void* buf, uint64_t len)
+int64 StripSuffixIo::read(void *buf, uint64 len)
 {
 {
 	if (!file)
 	if (!file)
 	{
 	{
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		return -1;
 		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);
 			PHYSFS_setErrorCode(PHYSFS_ERR_OK);
 			return 0;
 			return 0;
@@ -117,85 +117,59 @@ int64_t StripSuffixIo::read(void* buf, uint64_t len)
 			return -1;
 			return -1;
 		}
 		}
 	}
 	}
-	else if (ret < len && std::ferror(file))
-	{
-		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
-		return -1;
-	}
 	PHYSFS_setErrorCode(PHYSFS_ERR_OK);
 	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);
 	PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
 	return -1;
 	return -1;
 }
 }
 
 
-int64_t StripSuffixIo::seek(uint64_t offset)
+int64 StripSuffixIo::seek(uint64 offset)
 {
 {
 	if (!file)
 	if (!file)
 	{
 	{
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		return 0;
 		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)
 	if (!file)
 	{
 	{
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		return -1;
 		return -1;
 	}
 	}
-	return std::ftell(file);
+	return file->tell();
 }
 }
 
 
-int64_t StripSuffixIo::length()
+int64 StripSuffixIo::length()
 {
 {
 	return strippedLength_;
 	return strippedLength_;
 }
 }
 
 
-int64_t StripSuffixIo::flush()
+int64 StripSuffixIo::flush()
 {
 {
 	if (!file)
 	if (!file)
 	{
 	{
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
 		return 0;
 		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);
 		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
 } // physfs

+ 43 - 29
src/modules/filesystem/physfs/PhysfsIo.h

@@ -21,11 +21,11 @@
 #ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
 #ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
 #define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
 #define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
 
 
-#include <cstdint>
-#include <cstdio>
-#include <string>
-
 #include "libraries/physfs/physfs.h"
 #include "libraries/physfs/physfs.h"
+#include "common/int.h"
+#include "filesystem/DroppedFile.h"
+
+#include <string>
 
 
 namespace love
 namespace love
 {
 {
@@ -61,54 +61,54 @@ protected:
 private:
 private:
 
 
 	// Returns: number of bytes read, 0 on EOF, -1 on failure
 	// 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);
 		return derived(io)->read(buf, len);
 	}
 	}
 
 
 	// Returns: number of bytes written, -1 on failure
 	// 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);
 		return derived(io)->write(buf, len);
 	}
 	}
 
 
 	// Returns: non-zero on success, zero on error
 	// 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);
 		return derived(io)->seek(offset);
 	}
 	}
 
 
 	// Returns: current offset from start, -1 on error
 	// 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();
 		return derived(io)->tell();
 	}
 	}
 
 
 	// Returns: total size in bytes, -1 on error
 	// 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();
 		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
 		// Just use copy constructor
 		return new Derived(*derived(io));
 		return new Derived(*derived(io));
 	}
 	}
 
 
 	// Returns: non-zero on success, zero on error
 	// 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();
 		return derived(io)->flush();
 	}
 	}
 
 
-	static void staticDestroy(struct PHYSFS_Io* io)
+	static void staticDestroy(struct PHYSFS_Io *io)
 	{
 	{
 		// Just use destructor
 		// Just use destructor
 		delete derived(io);
 		delete derived(io);
 	}
 	}
 
 
-	static Derived* derived(PHYSFS_Io* io)
+	static Derived* derived(PHYSFS_Io *io)
 	{
 	{
 		return static_cast<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque));
 		return static_cast<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque));
 	}
 	}
@@ -116,46 +116,60 @@ private:
 
 
 struct StripSuffixIo : public PhysfsIo<StripSuffixIo>
 struct StripSuffixIo : public PhysfsIo<StripSuffixIo>
 {
 {
-	static const uint32_t version = 0;
+	static const uint32 version = 0;
 
 
 	std::string filename;
 	std::string filename;
-	FILE* file = nullptr;
+	DroppedFile *file = nullptr;
 
 
 	// The constructor is private in favor of this function to prevent stack allocation
 	// 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.
 	// 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()
 	virtual ~StripSuffixIo()
 	{
 	{
 		if (file)
 		if (file)
 		{
 		{
-			std::fclose(file);
+			file->release();
 		}
 		}
 	}
 	}
 
 
-	StripSuffixIo(const StripSuffixIo& other)
+	StripSuffixIo(const StripSuffixIo &other)
 		: StripSuffixIo(other.filename)
 		: StripSuffixIo(other.filename)
 	{
 	{
 	}
 	}
 
 
 	bool determineStrippedLength();
 	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:
 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;
 	int64_t strippedLength_ = -1;
 };
 };