Browse Source

File objects inherit from Stream.

Alex Szpakowski 3 years ago
parent
commit
d5865e160c

+ 1 - 1
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();

+ 20 - 53
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> 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<FileData> 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)
-{
-	return modes.find(in, out);
-}
-
-bool File::getConstant(Mode in, const char *&out)
-{
-	return modes.find(in, out);
-}
-
-std::vector<std::string> File::getConstants(Mode)
+STRINGMAP_CLASS_BEGIN(File, File::Mode, File::MODE_MAX_ENUM, mode)
 {
-	return modes.getNames();
+	{ "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(const char *in, BufferMode &out)
+STRINGMAP_CLASS_BEGIN(File, File::BufferMode, File::BUFFER_MAX_ENUM, bufferMode)
 {
-	return bufferModes.find(in, out);
+	{ "none", File::BUFFER_NONE },
+	{ "line", File::BUFFER_LINE },
+	{ "full", File::BUFFER_FULL },
 }
-
-bool File::getConstant(BufferMode in, const char *&out)
-{
-	return bufferModes.find(in, out);
-}
-
-std::vector<std::string> File::getConstants(BufferMode)
-{
-	return bufferModes.getNames();
-}
-
-StringMap<File::Mode, File::MODE_MAX_ENUM>::Entry File::modeEntries[] =
-{
-	{ "c", MODE_CLOSED },
-	{ "r", MODE_READ   },
-	{ "w", MODE_WRITE  },
-	{ "a", MODE_APPEND },
-};
-
-StringMap<File::Mode, File::MODE_MAX_ENUM> File::modes(File::modeEntries, sizeof(File::modeEntries));
-
-StringMap<File::BufferMode, File::BUFFER_MAX_ENUM>::Entry File::bufferModeEntries[] =
-{
-	{ "none", BUFFER_NONE },
-	{ "line", BUFFER_LINE },
-	{ "full", BUFFER_FULL },
-};
-
-StringMap<File::BufferMode, File::BUFFER_MAX_ENUM> File::bufferModes(File::bufferModeEntries, sizeof(File::bufferModeEntries));
+STRINGMAP_CLASS_END(File, File::BufferMode, File::BUFFER_MAX_ENUM, bufferMode)
 
 } // filesystem
 } // love

+ 15 - 78
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.
-	 * @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.
+	 * @return A newly allocated Data object.
 	 **/
-	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<std::string> getConstants(Mode);
-
-	static bool getConstant(const char *in, BufferMode &out);
-	static bool getConstant(BufferMode in, const char *&out);
-	static std::vector<std::string> getConstants(BufferMode);
-
-private:
-
-	static StringMap<Mode, MODE_MAX_ENUM>::Entry modeEntries[];
-	static StringMap<Mode, MODE_MAX_ENUM> modes;
-
-	static StringMap<BufferMode, BUFFER_MAX_ENUM>::Entry bufferModeEntries[];
-	static StringMap<BufferMode, BUFFER_MAX_ENUM> bufferModes;
+	STRINGMAP_CLASS_DECLARE(Mode);
+	STRINGMAP_CLASS_DECLARE(BufferMode);
 
 }; // File
 

+ 3 - 2
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.

+ 30 - 4
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
 }
 

+ 12 - 7
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;

+ 32 - 6
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;
 }
 

+ 12 - 7
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;
 

+ 13 - 11
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);
 }
 
-void Filesystem::write(const char *filename, const void *data, int64 size) const
+FileData* Filesystem::read(const char* filename) const
 {
-	File file(filename);
+	File file(filename, File::MODE_READ);
+
+	// close() is called in the File destructor.
+	return file.read();
+}
 
-	file.open(File::MODE_WRITE);
+void Filesystem::write(const char *filename, const void *data, int64 size) const
+{
+	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))

+ 3 - 2
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;
 

+ 3 - 1
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)

+ 10 - 2
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)
 	{

+ 2 - 0
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);