Alex Szpakowski avatar Alex Szpakowski committed 02760c3

Added File:setBuffer/getBuffer, File:flush, and File:getMode.

Comments (0)

Files changed (6)

src/modules/filesystem/File.cpp

 	return modes.find(in, out);
 }
 
-bool File::getConstant(Mode in, const char  *&out)
+bool File::getConstant(Mode in, const char *&out)
 {
 	return modes.find(in, out);
 }
 
+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);
+}
+
 StringMap<File::Mode, File::MODE_MAX_ENUM>::Entry File::modeEntries[] =
 {
 	{"c", File::CLOSED},
 
 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", File::BUFFER_NONE},
+	{"line", File::BUFFER_LINE},
+	{"full", File::BUFFER_FULL},
+};
+
+StringMap<File::BufferMode, File::BUFFER_MAX_ENUM> File::bufferModes(File::bufferModeEntries, sizeof(File::bufferModeEntries));
+
 } // filesystem
 } // love

src/modules/filesystem/File.h

 		MODE_MAX_ENUM
 	};
 
+	enum BufferMode
+	{
+		BUFFER_NONE,
+		BUFFER_LINE,
+		BUFFER_FULL,
+		BUFFER_MAX_ENUM
+	};
+
 	/**
 	 * Used to indicate ALL data in a file.
 	 **/
 	virtual bool write(const Data *data, int64 size = ALL) = 0;
 
 	/**
+	 * Flushes the currently buffered file data to disk. Only applicable in
+	 * write mode.
+	 **/
+	virtual bool flush() = 0;
+
+	/**
 	 * Checks whether we are currently at end-of-file.
 	 *
 	 * @return True if EOF, 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
+	 * buffer's capacity is reached.
+	 * In the BUFFER_LINE mode, the file will also write to disk if a newline is
+	 * written.
+	 *
+	 * @param bufmode The buffer mode.
+	 * @param size The size in bytes of the buffer.
+	 **/
+	virtual bool setBuffer(BufferMode bufmode, int64 size) = 0;
+
+	/**
+	 * @param[out] size The size in bytes of the buffer.
+	 * @return The current buffer mode.
+	 **/
+	virtual BufferMode getBuffer(int64 &size) const = 0;
+
+	/**
 	 * Gets the current mode of the File.
 	 * @return The current mode of the File; CLOSED, READ, WRITE or APPEND.
 	 **/
 	virtual std::string getExtension() const = 0;
 
 	static bool getConstant(const char *in, Mode &out);
-	static bool getConstant(Mode in, const char  *&out);
+	static bool getConstant(Mode in, const char *&out);
+
+	static bool getConstant(const char *in, BufferMode &out);
+	static bool getConstant(BufferMode in, const char *&out);
 
 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;
+
 }; // File
 
 } // filesystem

src/modules/filesystem/physfs/File.cpp

 File::File(const std::string &filename)
 	: filename(filename)
 	, file(0)
-	, mode(filesystem::File::CLOSED)
+	, mode(CLOSED)
+	, bufferMode(BUFFER_NONE)
+	, bufferSize(0)
 {
 }
 
 		break;
 	}
 
+	if (file != 0 && !setBuffer(bufferMode, bufferSize))
+	{
+		// Revert to buffer defaults if we don't successfully set the buffer.
+		bufferMode = BUFFER_NONE;
+		bufferSize = 0;
+	}
+
 	return (file != 0);
 }
 
 	// Sadly, we'll have to clamp to 32 bits here
 	size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size;
 
-	int64 read = (int64)PHYSFS_read(file, dst, 1, (int) size);
+	if (size < 0)
+		throw love::Exception("Invalid read size.");
+
+	int64 read = (int64)PHYSFS_read(file, dst, 1, (PHYSFS_uint32) size);
 
 	return read;
 }
 	// Another clamp, for the time being.
 	size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size;
 
+	if (size < 0)
+		throw love::Exception("Invalid write size.");
+
 	// Try to write.
-	int64 written = static_cast<int64>(PHYSFS_write(file, data, 1, (int) size));
+	int64 written = static_cast<int64>(PHYSFS_write(file, data, 1, (PHYSFS_uint32) size));
 
 	// Check that correct amount of data was written.
 	if (written != size)
 		return false;
 
+	// Manually flush the buffer in BUFFER_LINE mode if we find a newline.
+	if (bufferMode == BUFFER_LINE && bufferSize > size)
+	{
+		if (memchr(data, '\n', (size_t) size) != NULL)
+			flush();
+	}
+
 	return true;
 }
 
 	return write(data->getData(), (size == ALL) ? data->getSize() : size);
 }
 
+bool File::flush()
+{
+	if (!file || (mode != WRITE && mode != APPEND))
+		throw love::Exception("File is not opened for writing.");
+
+	return PHYSFS_flush(file) != 0;
+}
+
 #ifdef LOVE_WINDOWS
 // MSVC doesn't like the 'this' keyword
 // well, we'll use 'that'.
 	if (file == 0)
 		return -1;
 
-	return (int64)PHYSFS_tell(file);
+	return (int64) PHYSFS_tell(file);
 }
 
 bool File::seek(uint64 pos)
 	if (file == 0)
 		return false;
 
-	if (!PHYSFS_seek(file, (PHYSFS_uint64)pos))
+	if (!PHYSFS_seek(file, (PHYSFS_uint64) pos))
 		return false;
 	return true;
 }
 
+bool File::setBuffer(BufferMode bufmode, int64 size)
+{
+	// No negativity allowed!
+	if (size < 0)
+		return false;
+
+	// If the file isn't open, we'll make sure the buffer values are set in
+	// File::open.
+	if (file == 0 || mode == CLOSED)
+	{
+		bufferMode = bufmode;
+		bufferSize = size;
+		return true;
+	}
+
+	int ret = 1;
+
+	switch (bufmode)
+	{
+	case BUFFER_NONE:
+	default:
+		ret = PHYSFS_setBuffer(file, 0);
+		size = 0;
+		break;
+	case BUFFER_LINE:
+	case BUFFER_FULL:
+		ret = PHYSFS_setBuffer(file, size);
+		break;
+	}
+
+	if (ret == 0)
+		return false;
+
+	bufferMode = bufmode;
+	bufferSize = size;
+
+	return true;
+}
+
+File::BufferMode File::getBuffer(int64 &size) const
+{
+	size = bufferSize;
+	return bufferMode;
+}
+
 std::string File::getFilename() const
 {
 	return filename;

src/modules/filesystem/physfs/File.h

 
 class File : public love::filesystem::File
 {
-private:
-
-	// filename
-	std::string filename;
-
-	// PHYSFS File handle.
-	PHYSFS_file *file;
-
-	// The current mode of the file.
-	Mode mode;
-
 public:
 
 	/**
 	int64 read(void *dst, int64 size);
 	bool write(const void *data, int64 size);
 	bool write(const Data *data, int64 size = ALL);
+	bool flush();
 	bool eof();
 	int64 tell();
 	bool seek(uint64 pos);
+	bool setBuffer(BufferMode bufmode, int64 size);
+	BufferMode getBuffer(int64 &size) const;
 	Mode getMode() const;
 	std::string getFilename() const;
 	std::string getExtension() const;
 
+private:
+
+	// filename
+	std::string filename;
+
+	// PHYSFS File handle.
+	PHYSFS_File *file;
+
+	// The current mode of the file.
+	Mode mode;
+
+	BufferMode bufferMode;
+	int64 bufferSize;
+
 }; // File
 
 } // physfs

src/modules/filesystem/physfs/wrap_File.cpp

 int w_File_write(lua_State *L)
 {
 	File *file = luax_checkfile(L, 1);
-	bool result;
+	bool result = false;
 
 	if (lua_isstring(L, 2))
 	{
 	return 1;
 }
 
+int w_File_flush(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	bool success = false;
+	try
+	{
+		success = file->flush();
+	}
+	catch (love::Exception &e)
+	{
+		return ioError(L, "%s", e.what());
+	}
+	luax_pushboolean(L, success);
+	return 1;
+}
+
 int w_File_eof(lua_State *L)
 {
 	File *file = luax_checkfile(L, 1);
 
 int w_File_lines(lua_State *L)
 {
-	File *file;
+	File *file = luax_checkfile(L, 1);
 
-	if (luax_istype(L, 1, FILESYSTEM_FILE_T))
-	{
-		file = luax_checktype<File>(L, 1, "File", FILESYSTEM_FILE_T);
-		lua_pushnumber(L, 0); // File position.
-		luax_pushboolean(L, file->getMode() != File::CLOSED); // Save current file mode.
-	}
-	else
-		return luaL_error(L, "Expected File.");
+	lua_pushnumber(L, 0); // File position.
+	luax_pushboolean(L, file->getMode() != File::CLOSED); // Save current file mode.
 
 	if (file->getMode() != File::READ)
 	{
 	return 1;
 }
 
+int w_File_setBuffer(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	const char *str = luaL_checkstring(L, 2);
+	int64 size = (int64) luaL_optnumber(L, 3, 0.0);
+
+	File::BufferMode bufmode;
+	if (!File::getConstant(str, bufmode))
+		return luaL_error(L, "Incorrect file buffer mode: %s", str);
+
+	bool success = false;
+	try
+	{
+		success = file->setBuffer(bufmode, size);
+	}
+	catch (love::Exception &e)
+	{
+		return ioError(L, "%s", e.what());
+	}
+
+	luax_pushboolean(L, success);
+	return 1;
+}
+
+int w_File_getBuffer(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	int64 size = 0;
+	File::BufferMode bufmode = file->getBuffer(size);
+	const char *str = 0;
+
+	if (!File::getConstant(bufmode, str))
+		return ioError(L, "Unknown file buffer mode.");
+
+	lua_pushstring(L, str);
+	lua_pushnumber(L, (lua_Number) size);
+	return 2;
+}
+
+int w_File_getMode(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+
+	File::Mode mode = file->getMode();
+	const char *str = 0;
+
+	if (!File::getConstant(mode, str))
+		return ioError(L, "Unknown file mode.");
+
+	lua_pushstring(L, str);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "getSize", w_File_getSize },
 	{ "isOpen", w_File_isOpen },
 	{ "read", w_File_read },
 	{ "write", w_File_write },
+	{ "flush", w_File_flush },
 	{ "eof", w_File_eof },
 	{ "tell", w_File_tell },
 	{ "seek", w_File_seek },
 	{ "lines", w_File_lines },
+	{ "setBuffer", w_File_setBuffer },
+	{ "getBuffer", w_File_getBuffer },
+	{ "getMode", w_File_getMode },
 	{ 0, 0 }
 };
 

src/modules/filesystem/physfs/wrap_File.h

 int w_File_isOpen(lua_State *L);
 int w_File_read(lua_State *L);
 int w_File_write(lua_State *L);
+int w_File_flush(lua_State *L);
 int w_File_eof(lua_State *L);
 int w_File_tell(lua_State *L);
 int w_File_seek(lua_State *L);
 int w_File_lines(lua_State *L);
+int w_File_setBuffer(lua_State *L);
+int w_File_getBuffer(lua_State *L);
+int w_File_getMode(lua_State *L);
 extern "C" int luaopen_file(lua_State *L);
 
 } // physfs
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.