Browse Source

Upgrade love.filesystem to use 64-bit numbers for dealing with file sizes, thus (hopefully) enabling lovers to work with very large files (based on Boolsheet's patch in issue #179)

Bill Meltsner 13 years ago
parent
commit
7378a90101

+ 9 - 8
src/modules/filesystem/File.h

@@ -28,6 +28,7 @@
 #include <common/Data.h>
 #include <common/Data.h>
 #include <common/Object.h>
 #include <common/Object.h>
 #include <common/StringMap.h>
 #include <common/StringMap.h>
+#include <common/int.h>
 
 
 namespace love
 namespace love
 {
 {
@@ -56,7 +57,7 @@ namespace filesystem
 		/**
 		/**
 		* Used to indicate ALL data in a file.
 		* Used to indicate ALL data in a file.
 		**/
 		**/
-		static const int ALL = -1;
+		static const int64 ALL = -1;
 
 
 		/**
 		/**
 		* Destructor.
 		* Destructor.
@@ -83,7 +84,7 @@ namespace filesystem
 		*
 		*
 		* @return The size of the file.
 		* @return The size of the file.
 		**/
 		**/
-		virtual unsigned int getSize() = 0;
+		virtual int64 getSize() = 0;
 
 
 		/**
 		/**
 		* Reads data from the file and allocates a Data object.
 		* Reads data from the file and allocates a Data object.
@@ -91,7 +92,7 @@ namespace filesystem
 		* @param size The number of bytes to attempt reading, or -1 for EOF.
 		* @param size The number of bytes to attempt reading, or -1 for EOF.
 		* @return A newly allocated Data object.
 		* @return A newly allocated Data object.
 		**/
 		**/
-		virtual Data * read(int size = ALL) = 0;
+		virtual Data * read(int64 size = ALL) = 0;
 
 
 		/**
 		/**
 		* Reads data into the destination buffer.
 		* Reads data into the destination buffer.
@@ -100,7 +101,7 @@ namespace filesystem
 		* @param size The number of bytes to attempt reading.
 		* @param size The number of bytes to attempt reading.
 		* @return The number of bytes actually read.
 		* @return The number of bytes actually read.
 		**/
 		**/
-		virtual int read(void * dst, int size) = 0;
+		virtual int64 read(void * dst, int64 size) = 0;
 
 
 		/**
 		/**
 		* Writes data into the File.
 		* Writes data into the File.
@@ -109,7 +110,7 @@ namespace filesystem
 		* @param size The size of the buffer.
 		* @param size The size of the buffer.
 		* @return True of success, false otherwise.
 		* @return True of success, false otherwise.
 		**/
 		**/
-		virtual bool write(const void * data, int size) = 0;
+		virtual bool write(const void * data, int64 size) = 0;
 
 
 		/**
 		/**
 		* Writes a Data object into the File.
 		* Writes a Data object into the File.
@@ -118,7 +119,7 @@ namespace filesystem
 		* @param size The number of bytes to attempt writing, or -1 for everything.
 		* @param size The number of bytes to attempt writing, or -1 for everything.
 		* @return True of success, false otherwise.
 		* @return True of success, false otherwise.
 		**/
 		**/
-		virtual bool write(const Data * data, int size = ALL) = 0;
+		virtual bool write(const Data * data, int64 size = ALL) = 0;
 
 
 		/**
 		/**
 		* Checks whether we are currently at end-of-file.
 		* Checks whether we are currently at end-of-file.
@@ -132,7 +133,7 @@ namespace filesystem
 		*
 		*
 		* @return The current byte position in the File.
 		* @return The current byte position in the File.
 		**/
 		**/
-		virtual int tell() = 0;
+		virtual int64 tell() = 0;
 
 
 		/**
 		/**
 		* Seeks to a certain position in the File.
 		* Seeks to a certain position in the File.
@@ -140,7 +141,7 @@ namespace filesystem
 		* @param pos The byte position in the file.
 		* @param pos The byte position in the file.
 		* @return True on success, false otherwise.
 		* @return True on success, false otherwise.
 		**/
 		**/
-		virtual bool seek(int pos) = 0;
+		virtual bool seek(uint64 pos) = 0;
 
 
 		/**
 		/**
 		* Gets the current mode of the File.
 		* Gets the current mode of the File.

+ 1 - 1
src/modules/filesystem/FileData.cpp

@@ -27,7 +27,7 @@ namespace love
 {
 {
 namespace filesystem
 namespace filesystem
 {
 {
-	FileData::FileData(int size, const std::string & filename)
+	FileData::FileData(unsigned int size, const std::string & filename)
 		: data(new char[size]), size(size), filename(filename)
 		: data(new char[size]), size(size), filename(filename)
 	{
 	{
 		if (filename.rfind('.') != std::string::npos)
 		if (filename.rfind('.') != std::string::npos)

+ 2 - 2
src/modules/filesystem/FileData.h

@@ -38,7 +38,7 @@ namespace filesystem
 		char * data;
 		char * data;
 
 
 		// Size of the data.
 		// Size of the data.
-		int size;
+		unsigned int size;
 
 
 		// The filename used for error purposes.
 		// The filename used for error purposes.
 		std::string filename;
 		std::string filename;
@@ -55,7 +55,7 @@ namespace filesystem
 			DECODE_MAX_ENUM
 			DECODE_MAX_ENUM
 		}; // Decoder
 		}; // Decoder
 
 
-		FileData(int size, const std::string & filename);
+		FileData(unsigned int size, const std::string & filename);
 
 
 		virtual ~FileData();
 		virtual ~FileData();
 
 

+ 14 - 14
src/modules/filesystem/physfs/File.cpp

@@ -92,30 +92,30 @@ namespace physfs
 		return true;
 		return true;
 	}
 	}
 
 
-	unsigned int File::getSize()
+	int64 File::getSize()
 	{
 	{
 		// If the file is closed, open it to
 		// If the file is closed, open it to
 		// check the size.
 		// check the size.
 		if (file == 0)
 		if (file == 0)
 		{
 		{
 			open(READ);
 			open(READ);
-			unsigned int size = (unsigned int)PHYSFS_fileLength(file);
+			int64 size = (int64)PHYSFS_fileLength(file);
 			close();
 			close();
 			return size;
 			return size;
 		}
 		}
 
 
-		return (unsigned int)PHYSFS_fileLength(file);
+		return (int64)PHYSFS_fileLength(file);
 	}
 	}
 
 
 
 
-	Data * File::read(int size)
+	Data * File::read(int64 size)
 	{
 	{
 		bool isOpen = (file != 0);
 		bool isOpen = (file != 0);
 
 
 		if (!isOpen && !open(READ))
 		if (!isOpen && !open(READ))
 			throw love::Exception("Could not read file %s.", filename.c_str());
 			throw love::Exception("Could not read file %s.", filename.c_str());
 
 
-		int max = (int)PHYSFS_fileLength(file);
+		int64 max = (int64)PHYSFS_fileLength(file);
 		size = (size == ALL) ? max : size;
 		size = (size == ALL) ? max : size;
 		size = (size > max) ? max : size;
 		size = (size > max) ? max : size;
 
 
@@ -129,18 +129,18 @@ namespace physfs
 		return fileData;
 		return fileData;
 	}
 	}
 
 
-	int File::read(void * dst, int size)
+	int64 File::read(void * dst, int64 size)
 	{
 	{
 		bool isOpen = (file != 0);
 		bool isOpen = (file != 0);
 
 
 		if (!isOpen)
 		if (!isOpen)
 			open(READ);
 			open(READ);
 
 
-		int max = (int)PHYSFS_fileLength(file);
+		int64 max = (int64)PHYSFS_fileLength(file);
 		size = (size == ALL) ? max : size;
 		size = (size == ALL) ? max : size;
 		size = (size > max) ? max : size;
 		size = (size > max) ? max : size;
 
 
-		int read = (int)PHYSFS_read(file, dst, 1, size);
+		int64 read = (int64)PHYSFS_read(file, dst, 1, size);
 
 
 		if (!isOpen)
 		if (!isOpen)
 			close();
 			close();
@@ -148,13 +148,13 @@ namespace physfs
 		return read;
 		return read;
 	}
 	}
 
 
-	bool File::write(const void * data, int size)
+	bool File::write(const void * data, int64 size)
 	{
 	{
 		if (file == 0)
 		if (file == 0)
 			throw love::Exception("Could not write to file. File not open.");
 			throw love::Exception("Could not write to file. File not open.");
 
 
 		// Try to write.
 		// Try to write.
-		int written = static_cast<int>(PHYSFS_write(file, data, 1, size));
+		int written = static_cast<int64>(PHYSFS_write(file, data, 1, size));
 
 
 		// Check that correct amount of data was written.
 		// Check that correct amount of data was written.
 		if (written != size)
 		if (written != size)
@@ -163,7 +163,7 @@ namespace physfs
 		return true;
 		return true;
 	}
 	}
 
 
-	bool File::write(const Data * data, int size)
+	bool File::write(const Data * data, int64 size)
 	{
 	{
 		return write(data->getData(), (size == ALL) ? data->getSize() : size);
 		return write(data->getData(), (size == ALL) ? data->getSize() : size);
 	}
 	}
@@ -192,15 +192,15 @@ namespace physfs
 		return false;
 		return false;
 	}
 	}
 
 
-	int File::tell()
+	int64 File::tell()
 	{
 	{
 		if (file == 0)
 		if (file == 0)
 			return -1;
 			return -1;
 
 
-		return (int)PHYSFS_tell(file);
+		return (int64)PHYSFS_tell(file);
 	}
 	}
 
 
-	bool File::seek(int pos)
+	bool File::seek(uint64 pos)
 	{
 	{
 		if (file == 0)
 		if (file == 0)
 			return false;
 			return false;

+ 7 - 7
src/modules/filesystem/physfs/File.h

@@ -67,14 +67,14 @@ namespace physfs
 		// Implements love::filesystem::File.
 		// Implements love::filesystem::File.
 		bool open(Mode mode);
 		bool open(Mode mode);
 		bool close();
 		bool close();
-		unsigned int getSize();
-		Data * read(int size = ALL);
-		int read(void * dst, int size);
-		bool write(const void * data, int size);
-		bool write(const Data * data, int size = ALL);
+		int64 getSize();
+		Data * read(int64 size = ALL);
+		int64 read(void * dst, int64 size);
+		bool write(const void * data, int64 size);
+		bool write(const Data * data, int64 size = ALL);
 		bool eof();
 		bool eof();
-		int tell();
-		bool seek(int pos);
+		int64 tell();
+		bool seek(uint64 pos);
 		Mode getMode();
 		Mode getMode();
 		std::string getFilename() const;
 		std::string getFilename() const;
 		std::string getExtension() const;
 		std::string getExtension() const;

+ 2 - 2
src/modules/filesystem/physfs/Filesystem.cpp

@@ -169,7 +169,7 @@ namespace physfs
 		return new File(filename);
 		return new File(filename);
 	}
 	}
 
 
-	FileData * Filesystem::newFileData(void * data, int size, const char * filename)
+	FileData * Filesystem::newFileData(void * data, unsigned int size, const char * filename)
 	{
 	{
 		FileData * fd = new FileData(size, std::string(filename));
 		FileData * fd = new FileData(size, std::string(filename));
 
 
@@ -315,7 +315,7 @@ namespace physfs
 
 
 		// Optionally, the caller can specify whether to read
 		// Optionally, the caller can specify whether to read
 		// the whole file, or just a part of it.
 		// the whole file, or just a part of it.
-		int count = luaL_optint(L, 2, file->getSize());
+		int count = luaL_optint(L, 2, (lua_Integer)file->getSize()); // FIXME
 
 
 		// Read the data.
 		// Read the data.
 		Data * data = file->read(count);
 		Data * data = file->read(count);

+ 3 - 2
src/modules/filesystem/physfs/Filesystem.h

@@ -30,6 +30,7 @@
 // LOVE
 // LOVE
 #include <common/Module.h>
 #include <common/Module.h>
 #include <common/config.h>
 #include <common/config.h>
+#include <common/int.h>
 #include <filesystem/FileData.h>
 #include <filesystem/FileData.h>
 #include "File.h"
 #include "File.h"
 
 
@@ -153,7 +154,7 @@ namespace physfs
 		* @param size The size of the data.
 		* @param size The size of the data.
 		* @param filename The full filename used to file type identification.
 		* @param filename The full filename used to file type identification.
 		**/
 		**/
-		FileData * newFileData(void * data, int size, const char * filename);
+		FileData * newFileData(void * data, unsigned int size, const char * filename);
 
 
 		/**
 		/**
 		* Creates a new FileData object from base64 data.
 		* Creates a new FileData object from base64 data.
@@ -261,7 +262,7 @@ namespace physfs
 		* Seek to a position within a file.
 		* Seek to a position within a file.
 		* @param pos The position to seek to.
 		* @param pos The position to seek to.
 		**/
 		**/
-		bool seek(File * file, int pos);
+		bool seek(File * file, uint64 pos);
 
 
 		/**
 		/**
 		* This "native" method returns a table of all
 		* This "native" method returns a table of all

+ 27 - 13
src/modules/filesystem/physfs/wrap_File.cpp

@@ -22,6 +22,7 @@
 
 
 #include <common/Data.h>
 #include <common/Data.h>
 #include <common/Exception.h>
 #include <common/Exception.h>
+#include <common/int.h>
 
 
 namespace love
 namespace love
 {
 {
@@ -37,14 +38,14 @@ namespace physfs
 	int w_File_getSize(lua_State * L)
 	int w_File_getSize(lua_State * L)
 	{
 	{
 		File * t = luax_checkfile(L, 1);
 		File * t = luax_checkfile(L, 1);
-		try
-		{
-			lua_pushinteger(L, t->getSize());
-		}
-		catch (Exception & e)
-		{
-			return luaL_error(L, e.what());
-		}
+		int64 size = t->getSize();
+		
+		// Push nil on failure or if size does not fit into a double precision floating-point number.
+		if (size == -1 || size >= 0x20000000000000LL)
+			lua_pushnil(L);
+		else
+			lua_pushnumber(L, (lua_Number)size);
+		
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -79,10 +80,12 @@ namespace physfs
 	{
 	{
 		File * file = luax_checkfile(L, 1);
 		File * file = luax_checkfile(L, 1);
 		Data * d = 0;
 		Data * d = 0;
+		
+		int64 size = (int64)luaL_optnumber(L, 2, file->getSize());
 
 
 		try
 		try
 		{
 		{
-			d = file->read(luaL_optint(L, 2, file->getSize()));
+			d = file->read(size);
 		}
 		}
 		catch (Exception e)
 		catch (Exception e)
 		{
 		{
@@ -136,22 +139,33 @@ namespace physfs
 	int w_File_eof(lua_State * L)
 	int w_File_eof(lua_State * L)
 	{
 	{
 		File * file = luax_checkfile(L, 1);
 		File * file = luax_checkfile(L, 1);
-		lua_pushboolean(L, file->eof() ? 1 : 0);
+		luax_pushboolean(L, file->eof());
 		return 1;
 		return 1;
 	}
 	}
 
 
 	int w_File_tell(lua_State * L)
 	int w_File_tell(lua_State * L)
 	{
 	{
 		File * file = luax_checkfile(L, 1);
 		File * file = luax_checkfile(L, 1);
-		lua_pushinteger(L, file->tell());
+		int64 pos = file->tell();
+		// Push nil on failure or if pos does not fit into a double precision floating-point number.
+		if (pos == -1 || pos >= 0x20000000000000LL)
+			lua_pushnil(L);
+		else
+			lua_pushnumber(L, (lua_Number)pos);
 		return 1;
 		return 1;
 	}
 	}
 
 
 	int w_File_seek(lua_State * L)
 	int w_File_seek(lua_State * L)
 	{
 	{
 		File * file = luax_checkfile(L, 1);
 		File * file = luax_checkfile(L, 1);
-		int pos = luaL_checkinteger(L, 2);
-		lua_pushboolean(L, file->seek(pos) ? 1 : 0);
+		lua_Number pos = luaL_checknumber(L, 2);
+		
+		// Push false on negative and precision-problematic numbers.
+		// Better fail than seek to an unknown position.
+		if (pos < 0.0 || pos >= 9007199254740992.0)
+			luax_pushboolean(L, false);
+		else
+			luax_pushboolean(L, file->seek((uint64)pos));
 		return 1;
 		return 1;
 	}
 	}