diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index 40abe8ca4..bde9d0bfb 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -420,7 +420,7 @@ Message *Event::convert(const SDL_Event &e) } else { - auto *file = new love::filesystem::NativeFile(e.drop.file); + auto *file = new love::filesystem::NativeFile(e.drop.file, love::filesystem::File::MODE_CLOSED); vargs.emplace_back(&love::filesystem::NativeFile::type, file); msg = new Message("filedropped", vargs); file->release(); diff --git a/src/modules/filesystem/File.cpp b/src/modules/filesystem/File.cpp index c3fc539f6..6538c8f85 100644 --- a/src/modules/filesystem/File.cpp +++ b/src/modules/filesystem/File.cpp @@ -25,12 +25,17 @@ namespace love namespace filesystem { -love::Type File::type("File", &Object::type); +love::Type File::type("File", &Stream::type); File::~File() { } +FileData *File::read() +{ + return read(getSize()); +} + FileData *File::read(int64 size) { bool isopen = isOpen(); @@ -40,7 +45,6 @@ FileData *File::read(int64 size) int64 max = getSize(); int64 cur = tell(); - size = (size == ALL) ? max : size; if (size < 0) throw love::Exception("Invalid read size."); @@ -54,7 +58,7 @@ FileData *File::read(int64 size) if (cur + size > max) size = max - cur; - FileData *fileData = new FileData(size, getFilename()); + StrongRef fileData(new FileData(size, getFilename()), Acquire::NORETAIN); int64 bytesRead = read(fileData->getData(), size); if (bytesRead < 0 || (bytesRead == 0 && bytesRead != size)) @@ -65,23 +69,18 @@ FileData *File::read(int64 size) if (bytesRead < size) { - FileData *tmpFileData = new FileData(bytesRead, getFilename()); + StrongRef tmpFileData(new FileData(bytesRead, getFilename()), Acquire::NORETAIN); memcpy(tmpFileData->getData(), fileData->getData(), (size_t) bytesRead); - fileData->release(); fileData = tmpFileData; } if (!isopen) close(); + fileData->retain(); return fileData; } -bool File::write(const Data *data, int64 size) -{ - return write(data->getData(), (size == ALL) ? data->getSize() : size); -} - std::string File::getExtension() const { const std::string &filename = getFilename(); @@ -93,54 +92,22 @@ std::string File::getExtension() const return std::string(); } -bool File::getConstant(const char *in, Mode &out) +STRINGMAP_CLASS_BEGIN(File, File::Mode, File::MODE_MAX_ENUM, mode) { - return modes.find(in, out); + { "c", File::MODE_CLOSED }, + { "r", File::MODE_READ }, + { "w", File::MODE_WRITE }, + { "a", File::MODE_APPEND }, } +STRINGMAP_CLASS_END(File, File::Mode, File::MODE_MAX_ENUM, mode) -bool File::getConstant(Mode in, const char *&out) +STRINGMAP_CLASS_BEGIN(File, File::BufferMode, File::BUFFER_MAX_ENUM, bufferMode) { - return modes.find(in, out); + { "none", File::BUFFER_NONE }, + { "line", File::BUFFER_LINE }, + { "full", File::BUFFER_FULL }, } - -std::vector File::getConstants(Mode) -{ - return modes.getNames(); -} - -bool File::getConstant(const char *in, BufferMode &out) -{ - return bufferModes.find(in, out); -} - -bool File::getConstant(BufferMode in, const char *&out) -{ - return bufferModes.find(in, out); -} - -std::vector File::getConstants(BufferMode) -{ - return bufferModes.getNames(); -} - -StringMap::Entry File::modeEntries[] = -{ - { "c", MODE_CLOSED }, - { "r", MODE_READ }, - { "w", MODE_WRITE }, - { "a", MODE_APPEND }, -}; - -StringMap File::modes(File::modeEntries, sizeof(File::modeEntries)); - -StringMap::Entry File::bufferModeEntries[] = -{ - { "none", BUFFER_NONE }, - { "line", BUFFER_LINE }, - { "full", BUFFER_FULL }, -}; - -StringMap File::bufferModes(File::bufferModeEntries, sizeof(File::bufferModeEntries)); +STRINGMAP_CLASS_END(File, File::BufferMode, File::BUFFER_MAX_ENUM, bufferMode) } // filesystem } // love diff --git a/src/modules/filesystem/File.h b/src/modules/filesystem/File.h index 902730470..4b7a74cd5 100644 --- a/src/modules/filesystem/File.h +++ b/src/modules/filesystem/File.h @@ -27,6 +27,7 @@ // LOVE #include "common/Data.h" #include "common/Object.h" +#include "common/Stream.h" #include "common/StringMap.h" #include "common/int.h" #include "FileData.h" @@ -40,7 +41,7 @@ namespace filesystem * A File interface, providing generic means of reading from and * writing to files. **/ -class File : public Object +class File : public Stream { public: @@ -66,16 +67,19 @@ public: BUFFER_MAX_ENUM }; - /** - * Used to indicate ALL data in a file. - **/ - static const int64 ALL = -1; - /** * Destructor. **/ virtual ~File(); + // Implements Stream. + bool isReadable() const override { return getMode() == MODE_READ; } + bool isWritable() const override { return getMode() == MODE_WRITE || getMode() == MODE_APPEND; } + bool isSeekable() const override { return isOpen(); } + + using Stream::read; + using Stream::write; + /** * Opens the file in a certain mode. * @@ -96,53 +100,14 @@ public: **/ virtual bool isOpen() const = 0; - /** - * Gets the size of the file. - * - * @return The size of the file. - **/ - virtual int64 getSize() = 0; - /** * Reads data from the file and allocates a Data object. * - * @param size The number of bytes to attempt reading, or -1 for EOF. + * @param size The number of bytes to attempt reading. * @return A newly allocated Data object. **/ - virtual FileData *read(int64 size = ALL); - - /** - * Reads data into the destination buffer. - * - * @param dst The destination buffer. - * @param size The number of bytes to attempt reading. - * @return The number of bytes actually read. - **/ - virtual int64 read(void *dst, int64 size) = 0; - - /** - * Writes data into the File. - * - * @param data The source buffer. - * @param size The size of the buffer. - * @return True of success, false otherwise. - **/ - virtual bool write(const void *data, int64 size) = 0; - - /** - * Writes a Data object into the File. - * - * @param data The data object to write into the file. - * @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, int64 size = ALL); - - /** - * Flushes the currently buffered file data to disk. Only applicable in - * write mode. - **/ - virtual bool flush() = 0; + FileData *read(int64 size) override; + FileData *read(); /** * Checks whether we are currently at end-of-file. @@ -151,21 +116,6 @@ public: **/ virtual bool isEOF() = 0; - /** - * Gets the current position in the File. - * - * @return The current byte position in the File. - **/ - virtual int64 tell() = 0; - - /** - * Seeks to a certain position in the File. - * - * @param pos The byte position in the file. - * @return True on success, false otherwise. - **/ - virtual bool seek(uint64 pos) = 0; - /** * Sets the buffering mode for the file. When buffering is enabled, the file * will not write to disk (or will pre-load data if in read mode) until the @@ -202,21 +152,8 @@ public: **/ virtual std::string getExtension() const; - static bool getConstant(const char *in, Mode &out); - static bool getConstant(Mode in, const char *&out); - static std::vector getConstants(Mode); - - static bool getConstant(const char *in, BufferMode &out); - static bool getConstant(BufferMode in, const char *&out); - static std::vector getConstants(BufferMode); - -private: - - static StringMap::Entry modeEntries[]; - static StringMap modes; - - static StringMap::Entry bufferModeEntries[]; - static StringMap bufferModes; + STRINGMAP_CLASS_DECLARE(Mode); + STRINGMAP_CLASS_DECLARE(BufferMode); }; // File diff --git a/src/modules/filesystem/Filesystem.h b/src/modules/filesystem/Filesystem.h index 4a381c75c..53ca5cdbb 100644 --- a/src/modules/filesystem/Filesystem.h +++ b/src/modules/filesystem/Filesystem.h @@ -167,7 +167,7 @@ public: /** * Creates a new file. **/ - virtual File *newFile(const char *filename) const = 0; + virtual File *newFile(const char *filename, File::Mode = File::MODE_CLOSED) const = 0; /** * Creates a new FileData object. Data will be copied. @@ -239,7 +239,8 @@ public: * @param filename The name of the file to read from. * @param size The size in bytes of the data to read. **/ - virtual FileData *read(const char *filename, int64 size = File::ALL) const = 0; + virtual FileData *read(const char *filename, int64 size) const = 0; + virtual FileData *read(const char *filename) const = 0; /** * Write data to a file. diff --git a/src/modules/filesystem/NativeFile.cpp b/src/modules/filesystem/NativeFile.cpp index fad7432fb..0fd5d0f1d 100644 --- a/src/modules/filesystem/NativeFile.cpp +++ b/src/modules/filesystem/NativeFile.cpp @@ -39,13 +39,14 @@ namespace filesystem love::Type NativeFile::type("NativeFile", &File::type); -NativeFile::NativeFile(const std::string &filename) +NativeFile::NativeFile(const std::string &filename, Mode mode) : filename(filename) , file(nullptr) , mode(MODE_CLOSED) , bufferMode(BUFFER_NONE) , bufferSize(0) { + open(mode); } NativeFile::~NativeFile() @@ -54,10 +55,28 @@ NativeFile::~NativeFile() close(); } +NativeFile::NativeFile(const NativeFile &other) + : filename(other.filename) + , file(nullptr) + , mode(MODE_CLOSED) + , bufferMode(other.bufferMode) + , bufferSize(other.bufferSize) +{ + open(other.mode); +} + +NativeFile *NativeFile::clone() +{ + return new NativeFile(*this); +} + bool NativeFile::open(Mode newmode) { if (newmode == MODE_CLOSED) + { + close(); return true; + } // File already open? if (file != nullptr) @@ -197,15 +216,22 @@ int64 NativeFile::tell() #endif } -bool NativeFile::seek(uint64 pos) +bool NativeFile::seek(int64 pos, SeekOrigin origin) { if (file == nullptr) return false; + int forigin = SEEK_SET; + if (origin == SEEKORIGIN_CURRENT) + forigin = SEEK_CUR; + else if (origin == SEEKORIGIN_END) + forigin = SEEK_END; + + // TODO #ifdef LOVE_WINDOWS - return _fseeki64(file, (int64) pos, SEEK_SET) == 0; + return _fseeki64(file, pos, forigin) == 0; #else - return fseeko(file, (off_t) pos, SEEK_SET) == 0; + return fseeko(file, (off_t) pos, forigin) == 0; #endif } diff --git a/src/modules/filesystem/NativeFile.h b/src/modules/filesystem/NativeFile.h index 4a3e23e5c..9809784e8 100644 --- a/src/modules/filesystem/NativeFile.h +++ b/src/modules/filesystem/NativeFile.h @@ -39,22 +39,25 @@ public: static love::Type type; - NativeFile(const std::string &filename); + NativeFile(const std::string &filename, Mode mode); virtual ~NativeFile(); + // Implements Stream. + NativeFile *clone() override; + int64 read(void* dst, int64 size) override; + bool write(const void* data, int64 size) override; + bool flush() override; + int64 getSize() override; + int64 tell() override; + bool seek(int64 pos, SeekOrigin origin) override; + // Implements File. using File::read; using File::write; bool open(Mode mode) override; bool close() override; bool isOpen() const override; - int64 getSize() override; - int64 read(void *dst, int64 size) override; - bool write(const void *data, int64 size) override; - bool flush() override; bool isEOF() override; - int64 tell() override; - bool seek(uint64 pos) override; bool setBuffer(BufferMode bufmode, int64 size) override; BufferMode getBuffer(int64 &size) const override; Mode getMode() const override; @@ -62,6 +65,8 @@ public: private: + NativeFile(const NativeFile &other); + static const char *getModeString(Mode mode); std::string filename; diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 2caa2fc93..f56455fc5 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -41,13 +41,24 @@ static bool setupWriteDirectory() return fs != nullptr && fs->setupWriteDirectory(); } -File::File(const std::string &filename) +File::File(const std::string &filename, Mode mode) : filename(filename) , file(nullptr) , mode(MODE_CLOSED) , bufferMode(BUFFER_NONE) , bufferSize(0) { + open(mode); +} + +File::File(const File &other) + : filename(other.filename) + , file(nullptr) + , mode(MODE_CLOSED) + , bufferMode(other.bufferMode) + , bufferSize(other.bufferSize) +{ + open(other.mode); } File::~File() @@ -56,10 +67,18 @@ File::~File() close(); } +File *File::clone() +{ + return new File(*this); +} + bool File::open(Mode mode) { if (mode == MODE_CLOSED) + { + close(); return true; + } if (!PHYSFS_isInit()) throw love::Exception("PhysFS is not initialized."); @@ -151,10 +170,6 @@ int64 File::read(void *dst, int64 size) if (!file || mode != MODE_READ) throw love::Exception("File is not opened for reading."); - int64 max = (int64)PHYSFS_fileLength(file); - size = (size == ALL) ? max : size; - size = (size > max) ? max : size; - if (size < 0) throw love::Exception("Invalid read size."); @@ -207,8 +222,19 @@ int64 File::tell() return (int64) PHYSFS_tell(file); } -bool File::seek(uint64 pos) +bool File::seek(int64 pos, SeekOrigin origin) { + if (file != nullptr) + { + if (origin == SEEKORIGIN_CURRENT) + pos += tell(); + else if (origin == SEEKORIGIN_END) + pos += getSize(); + } + + if (pos < 0) + return false; + return file != nullptr && PHYSFS_seek(file, (PHYSFS_uint64) pos) != 0; } diff --git a/src/modules/filesystem/physfs/File.h b/src/modules/filesystem/physfs/File.h index 13dc543ca..40bad82a6 100644 --- a/src/modules/filesystem/physfs/File.h +++ b/src/modules/filesystem/physfs/File.h @@ -46,23 +46,26 @@ public: * Constructs an File with the given ilename. * @param filename The relative filepath of the file to load. **/ - File(const std::string &filename); + File(const std::string &filename, Mode mode); virtual ~File(); + // Implements Stream. + File *clone() override; + int64 read(void* dst, int64 size) override; + bool write(const void* data, int64 size) override; + bool flush() override; + int64 getSize() override; + bool seek(int64 pos, SeekOrigin origin) override; + int64 tell() override; + // Implements love::filesystem::File. using love::filesystem::File::read; using love::filesystem::File::write; bool open(Mode mode) override; bool close() override; bool isOpen() const override; - int64 getSize() override; - virtual int64 read(void *dst, int64 size) override; - bool write(const void *data, int64 size) override; - bool flush() override; bool isEOF() override; - int64 tell() override; - bool seek(uint64 pos) override; bool setBuffer(BufferMode bufmode, int64 size) override; BufferMode getBuffer(int64 &size) const override; Mode getMode() const override; @@ -70,6 +73,8 @@ public: private: + File(const File &other); + // filename std::string filename; diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index a56b0d527..4a2752d5e 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -496,9 +496,9 @@ bool Filesystem::unmount(Data *data) return false; } -love::filesystem::File *Filesystem::newFile(const char *filename) const +love::filesystem::File *Filesystem::newFile(const char *filename, File::Mode mode) const { - return new File(filename); + return new File(filename, mode); } std::string Filesystem::getFullCommonPath(CommonPath path) @@ -793,19 +793,23 @@ bool Filesystem::remove(const char *file) FileData *Filesystem::read(const char *filename, int64 size) const { - File file(filename); - - file.open(File::MODE_READ); + File file(filename, File::MODE_READ); // close() is called in the File destructor. return file.read(size); } +FileData* Filesystem::read(const char* filename) const +{ + File file(filename, File::MODE_READ); + + // close() is called in the File destructor. + return file.read(); +} + void Filesystem::write(const char *filename, const void *data, int64 size) const { - File file(filename); - - file.open(File::MODE_WRITE); + File file(filename, File::MODE_WRITE); // close() is called in the File destructor. if (!file.write(data, size)) @@ -814,9 +818,7 @@ void Filesystem::write(const char *filename, const void *data, int64 size) const void Filesystem::append(const char *filename, const void *data, int64 size) const { - File file(filename); - - file.open(File::MODE_APPEND); + File file(filename, File::MODE_APPEND); // close() is called in the File destructor. if (!file.write(data, size)) diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index 1e7854029..9b31c5f9f 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/src/modules/filesystem/physfs/Filesystem.h @@ -71,7 +71,7 @@ public: bool unmount(CommonPath path) override; bool unmountFullPath(const char *fullpath) override; - love::filesystem::File *newFile(const char *filename) const override; + love::filesystem::File *newFile(const char *filename, File::Mode mode = File::MODE_CLOSED) const override; std::string getFullCommonPath(CommonPath path) override; const char *getWorkingDirectory() override; @@ -88,7 +88,8 @@ public: bool remove(const char *file) override; - FileData *read(const char *filename, int64 size = File::ALL) const override; + FileData *read(const char *filename, int64 size) const override; + FileData *read(const char *filename) const override; void write(const char *filename, const void *data, int64 size) const override; void append(const char *filename, const void *data, int64 size) const override; diff --git a/src/modules/filesystem/wrap_File.cpp b/src/modules/filesystem/wrap_File.cpp index 6300ac183..4581010d8 100644 --- a/src/modules/filesystem/wrap_File.cpp +++ b/src/modules/filesystem/wrap_File.cpp @@ -121,10 +121,12 @@ int w_File_read(lua_State *L) startidx = 3; } - int64 size = (int64) luaL_optnumber(L, startidx, (lua_Number) File::ALL); + int64 size = (int64) luaL_optnumber(L, startidx, -1); try { + if (size < 0) + size = file->getSize(); d.set(file->read(size), Acquire::NORETAIN); } catch (love::Exception &e) diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index d7fd00e7f..fb239915d 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -343,6 +343,11 @@ Data *luax_getdata(lua_State *L, int idx) return data; } +bool luax_cangetfile(lua_State *L, int idx) +{ + return lua_isstring(L, idx) || luax_istype(L, idx, File::type); +} + bool luax_cangetfiledata(lua_State *L, int idx) { return lua_isstring(L, idx) || luax_istype(L, idx, File::type) || luax_istype(L, idx, FileData::type); @@ -557,12 +562,15 @@ int w_read(lua_State *L) } const char *filename = luaL_checkstring(L, startidx + 0); - int64 len = (int64) luaL_optinteger(L, startidx + 1, File::ALL); + int64 len = (int64) luaL_optinteger(L, startidx + 1, -1); FileData *data = nullptr; try { - data = instance()->read(filename, len); + if (len >= 0) + data = instance()->read(filename, len); + else + data = instance()->read(filename); } catch (love::Exception &e) { diff --git a/src/modules/filesystem/wrap_Filesystem.h b/src/modules/filesystem/wrap_Filesystem.h index 5474d3717..6d1667bf2 100644 --- a/src/modules/filesystem/wrap_Filesystem.h +++ b/src/modules/filesystem/wrap_Filesystem.h @@ -40,7 +40,9 @@ namespace filesystem **/ FileData *luax_getfiledata(lua_State *L, int idx); bool luax_cangetfiledata(lua_State *L, int idx); + File *luax_getfile(lua_State *L, int idx); +bool luax_cangetfile(lua_State *L, int idx); Data *luax_getdata(lua_State *L, int idx); bool luax_cangetdata(lua_State *L, int idx);