From 7378a90101ca55aad9dcdfe3df250818e2cdac82 Mon Sep 17 00:00:00 2001 From: Bill Meltsner Date: Thu, 22 Dec 2011 02:45:11 -0600 Subject: [PATCH] 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) --- src/modules/filesystem/File.h | 17 +++++---- src/modules/filesystem/FileData.cpp | 2 +- src/modules/filesystem/FileData.h | 4 +- src/modules/filesystem/physfs/File.cpp | 28 +++++++------- src/modules/filesystem/physfs/File.h | 14 +++---- src/modules/filesystem/physfs/Filesystem.cpp | 4 +- src/modules/filesystem/physfs/Filesystem.h | 5 ++- src/modules/filesystem/physfs/wrap_File.cpp | 40 +++++++++++++------- 8 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/modules/filesystem/File.h b/src/modules/filesystem/File.h index a4b3948da..46e70dfca 100644 --- a/src/modules/filesystem/File.h +++ b/src/modules/filesystem/File.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace love { @@ -56,7 +57,7 @@ namespace filesystem /** * Used to indicate ALL data in a file. **/ - static const int ALL = -1; + static const int64 ALL = -1; /** * Destructor. @@ -83,7 +84,7 @@ namespace filesystem * * @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. @@ -91,7 +92,7 @@ namespace filesystem * @param size The number of bytes to attempt reading, or -1 for EOF. * @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. @@ -100,7 +101,7 @@ namespace filesystem * @param size The number of bytes to attempt reading. * @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. @@ -109,7 +110,7 @@ namespace filesystem * @param size The size of the buffer. * @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. @@ -118,7 +119,7 @@ namespace filesystem * @param size The number of bytes to attempt writing, or -1 for everything. * @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. @@ -132,7 +133,7 @@ namespace filesystem * * @return The current byte position in the File. **/ - virtual int tell() = 0; + virtual int64 tell() = 0; /** * Seeks to a certain position in the File. @@ -140,7 +141,7 @@ namespace filesystem * @param pos The byte position in the file. * @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. diff --git a/src/modules/filesystem/FileData.cpp b/src/modules/filesystem/FileData.cpp index 33e31301f..32466aa85 100644 --- a/src/modules/filesystem/FileData.cpp +++ b/src/modules/filesystem/FileData.cpp @@ -27,7 +27,7 @@ namespace love { 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) { if (filename.rfind('.') != std::string::npos) diff --git a/src/modules/filesystem/FileData.h b/src/modules/filesystem/FileData.h index 938cc76aa..67160e8c8 100644 --- a/src/modules/filesystem/FileData.h +++ b/src/modules/filesystem/FileData.h @@ -38,7 +38,7 @@ namespace filesystem char * data; // Size of the data. - int size; + unsigned int size; // The filename used for error purposes. std::string filename; @@ -55,7 +55,7 @@ namespace filesystem DECODE_MAX_ENUM }; // Decoder - FileData(int size, const std::string & filename); + FileData(unsigned int size, const std::string & filename); virtual ~FileData(); diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index dc148435a..2561164c3 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -92,30 +92,30 @@ namespace physfs return true; } - unsigned int File::getSize() + int64 File::getSize() { // If the file is closed, open it to // check the size. if (file == 0) { open(READ); - unsigned int size = (unsigned int)PHYSFS_fileLength(file); + int64 size = (int64)PHYSFS_fileLength(file); close(); 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); if (!isOpen && !open(READ)) 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 > max) ? max : size; @@ -129,18 +129,18 @@ namespace physfs return fileData; } - int File::read(void * dst, int size) + int64 File::read(void * dst, int64 size) { bool isOpen = (file != 0); if (!isOpen) open(READ); - int max = (int)PHYSFS_fileLength(file); + int64 max = (int64)PHYSFS_fileLength(file); size = (size == ALL) ? 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) close(); @@ -148,13 +148,13 @@ namespace physfs return read; } - bool File::write(const void * data, int size) + bool File::write(const void * data, int64 size) { if (file == 0) throw love::Exception("Could not write to file. File not open."); // Try to write. - int written = static_cast(PHYSFS_write(file, data, 1, size)); + int written = static_cast(PHYSFS_write(file, data, 1, size)); // Check that correct amount of data was written. if (written != size) @@ -163,7 +163,7 @@ namespace physfs 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); } @@ -192,15 +192,15 @@ namespace physfs return false; } - int File::tell() + int64 File::tell() { if (file == 0) 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) return false; diff --git a/src/modules/filesystem/physfs/File.h b/src/modules/filesystem/physfs/File.h index aa6c682f2..59a3a0ffb 100644 --- a/src/modules/filesystem/physfs/File.h +++ b/src/modules/filesystem/physfs/File.h @@ -67,14 +67,14 @@ namespace physfs // Implements love::filesystem::File. bool open(Mode mode); 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(); - int tell(); - bool seek(int pos); + int64 tell(); + bool seek(uint64 pos); Mode getMode(); std::string getFilename() const; std::string getExtension() const; diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index f96d7f017..25068fe57 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -169,7 +169,7 @@ namespace physfs 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)); @@ -315,7 +315,7 @@ namespace physfs // Optionally, the caller can specify whether to read // 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. Data * data = file->read(count); diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index d87881059..92cd83e3d 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/src/modules/filesystem/physfs/Filesystem.h @@ -30,6 +30,7 @@ // LOVE #include #include +#include #include #include "File.h" @@ -153,7 +154,7 @@ namespace physfs * @param size The size of the data. * @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. @@ -261,7 +262,7 @@ namespace physfs * Seek to a position within a file. * @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 diff --git a/src/modules/filesystem/physfs/wrap_File.cpp b/src/modules/filesystem/physfs/wrap_File.cpp index 77c69786b..430c2860d 100644 --- a/src/modules/filesystem/physfs/wrap_File.cpp +++ b/src/modules/filesystem/physfs/wrap_File.cpp @@ -22,6 +22,7 @@ #include #include +#include namespace love { @@ -37,14 +38,14 @@ namespace physfs int w_File_getSize(lua_State * L) { 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; } @@ -79,10 +80,12 @@ namespace physfs { File * file = luax_checkfile(L, 1); Data * d = 0; + + int64 size = (int64)luaL_optnumber(L, 2, file->getSize()); try { - d = file->read(luaL_optint(L, 2, file->getSize())); + d = file->read(size); } catch (Exception e) { @@ -136,22 +139,33 @@ namespace physfs int w_File_eof(lua_State * L) { File * file = luax_checkfile(L, 1); - lua_pushboolean(L, file->eof() ? 1 : 0); + luax_pushboolean(L, file->eof()); return 1; } int w_File_tell(lua_State * L) { 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; } int w_File_seek(lua_State * L) { 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; }