Commits

Alex Szpakowski committed 060c0d6 Merge

Merged default into minor

  • Participants
  • Parent commits 145524a, cb3df7e
  • Branches minor

Comments (0)

Files changed (76)

File CMakeLists.txt

 	src/modules/filesystem/File.h
 	src/modules/filesystem/FileData.cpp
 	src/modules/filesystem/FileData.h
+	src/modules/filesystem/wrap_File.cpp
+	src/modules/filesystem/wrap_File.h
+	src/modules/filesystem/wrap_FileData.cpp
+	src/modules/filesystem/wrap_FileData.h
+	src/modules/filesystem/wrap_Filesystem.cpp
+	src/modules/filesystem/wrap_Filesystem.h
 )
 
 set(LOVE_SRC_MODULE_FILESYSTEM_PHYSFS
 	src/modules/filesystem/physfs/File.h
 	src/modules/filesystem/physfs/Filesystem.cpp
 	src/modules/filesystem/physfs/Filesystem.h
-	src/modules/filesystem/physfs/wrap_File.cpp
-	src/modules/filesystem/physfs/wrap_File.h
-	src/modules/filesystem/physfs/wrap_FileData.cpp
-	src/modules/filesystem/physfs/wrap_FileData.h
-	src/modules/filesystem/physfs/wrap_Filesystem.cpp
-	src/modules/filesystem/physfs/wrap_Filesystem.h
 )
 
 set(LOVE_SRC_MODULE_FILESYSTEM
 	src/modules/joystick/Joystick.cpp
 	src/modules/joystick/Joystick.h
 	src/modules/joystick/JoystickModule.h
+	src/modules/joystick/wrap_Joystick.cpp
+	src/modules/joystick/wrap_Joystick.h
+	src/modules/joystick/wrap_JoystickModule.cpp
+	src/modules/joystick/wrap_JoystickModule.h
 )
 
 set(LOVE_SRC_MODULE_JOYSTICK_SDL
 	src/modules/joystick/sdl/Joystick.h
 	src/modules/joystick/sdl/JoystickModule.cpp
 	src/modules/joystick/sdl/JoystickModule.h
-	src/modules/joystick/sdl/wrap_Joystick.cpp
-	src/modules/joystick/sdl/wrap_Joystick.h
-	src/modules/joystick/sdl/wrap_JoystickModule.cpp
-	src/modules/joystick/sdl/wrap_JoystickModule.h
 )
 
 set(LOVE_SRC_MODULE_JOYSTICK

File platform/macosx/love-framework.xcodeproj/project.pbxproj

 				FAB0078E1740C12D00A9664D /* Joystick.h */,
 				4C606AEC342457600C3F0741 /* JoystickModule.h */,
 				687216AD6FA406C838284B91 /* sdl */,
+				FAB007951740C87D00A9664D /* wrap_Joystick.cpp */,
+				FAB007961740C87D00A9664D /* wrap_Joystick.h */,
+				139411436818381E493F00F5 /* wrap_JoystickModule.cpp */,
+				2D7B7DEC4FC87878332E41B3 /* wrap_JoystickModule.h */,
 			);
 			path = joystick;
 			sourceTree = "<group>";
 				47D46915001F342A3CD23E86 /* File.h */,
 				6DE3129F3A0B2D9C178118F3 /* Filesystem.cpp */,
 				219636CF6780074F7871463D /* Filesystem.h */,
-				6C367AE309C453C412D91363 /* wrap_File.cpp */,
-				52E15B702C40593D3BF431DF /* wrap_File.h */,
-				597478A255B82B56488B4717 /* wrap_FileData.cpp */,
-				3512460642B046876D687B22 /* wrap_FileData.h */,
-				1E827AE8548C52493ED95629 /* wrap_Filesystem.cpp */,
-				5DC271240F0119AE16FA1B8E /* wrap_Filesystem.h */,
 			);
 			path = physfs;
 			sourceTree = "<group>";
 				FAB007921740C28900A9664D /* Joystick.h */,
 				55B425307C0C1C4B3EFC3A5F /* JoystickModule.cpp */,
 				439E46D768A266780E894800 /* JoystickModule.h */,
-				FAB007951740C87D00A9664D /* wrap_Joystick.cpp */,
-				FAB007961740C87D00A9664D /* wrap_Joystick.h */,
-				139411436818381E493F00F5 /* wrap_JoystickModule.cpp */,
-				2D7B7DEC4FC87878332E41B3 /* wrap_JoystickModule.h */,
 			);
 			path = sdl;
 			sourceTree = "<group>";
 				62370A494F9D6E2D570065EB /* FileData.cpp */,
 				54A13C2209F945671BC27974 /* FileData.h */,
 				64DD03B45BF6265723662DAF /* physfs */,
+				6C367AE309C453C412D91363 /* wrap_File.cpp */,
+				52E15B702C40593D3BF431DF /* wrap_File.h */,
+				597478A255B82B56488B4717 /* wrap_FileData.cpp */,
+				3512460642B046876D687B22 /* wrap_FileData.h */,
+				1E827AE8548C52493ED95629 /* wrap_Filesystem.cpp */,
+				5DC271240F0119AE16FA1B8E /* wrap_Filesystem.h */,
 			);
 			path = filesystem;
 			sourceTree = "<group>";

File src/common/runtime.cpp

 
 int luax_convobj(lua_State *L, int idx, const char *mod, const char *fn)
 {
+	// Convert to absolute index if necessary.
+	if (idx < 0 && idx > LUA_REGISTRYINDEX)
+		idx += lua_gettop(L) + 1;
+
 	// Convert string to a file.
 	luax_getfunction(L, mod, fn);
 	lua_pushvalue(L, idx); // The initial argument.

File src/common/runtime.h

 	#include <lauxlib.h>
 }
 
+// C++
+#include <exception>
+
 namespace love
 {
 
 Type luax_type(lua_State *L, int idx);
 
 /**
- * Macro for converting a LOVE exception into a Lua error.
+ * Converts any exceptions thrown by the passed lambda function into a Lua error.
  * lua_error (and luaL_error) cannot be called from inside the exception handler
  * because they use longjmp, which causes undefined behaviour when the
  * destructor of the exception would have been called.
  **/
-#define EXCEPT_GUARD(A) \
-{ \
-	bool should_error = false; \
-	try { A } \
-	catch (love::Exception &e) \
-	{ \
-		should_error = true; \
-		lua_pushstring(L, e.what()); \
-	} \
-	if (should_error) \
-		return luaL_error(L, "%s", lua_tostring(L, -1)); \
+template <typename T>
+int luax_catchexcept(lua_State *L, const T& func)
+{
+	bool should_error = false;
+
+	try
+	{
+		func();
+	}
+	catch (const std::exception &e)
+	{
+		should_error = true;
+		lua_pushstring(L, e.what());
+	}
+
+	if (should_error)
+		return luaL_error(L, "%s", lua_tostring(L, -1));
+
+	return 0;
+
+}
+
+template <typename T, typename F>
+int luax_catchexcept(lua_State *L, const T& func, const F& finallyfunc)
+{
+	bool should_error = false;
+
+	try
+	{
+		func();
+	}
+	catch (const std::exception &e)
+	{
+		should_error = true;
+		lua_pushstring(L, e.what());
+	}
+
+	finallyfunc();
+
+	if (should_error)
+		return luaL_error(L, "%s", lua_tostring(L, -1));
+	
+	return 0;
+	
 }
 
 } // love

File src/modules/audio/openal/Source.cpp

 {
 	// Get more sound data.
 	int decoded = d->decode();
+	decoded = decoded >= 0 ? decoded : 0;
 
 	int fmt = getFormat(d->getChannels(), d->getBitDepth());
 

File src/modules/audio/wrap_Audio.cpp

 
 int w_newSource(lua_State *L)
 {
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
-	if (luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 		luax_convobj(L, 1, "sound", "newDecoder");
 
 	Source::Type stype = Source::TYPE_STREAM;

File src/modules/audio/wrap_Source.cpp

 {
 	Source *t = luax_checksource(L, 1);
 	Source *clone = nullptr;
-	EXCEPT_GUARD(clone = t->clone();)
+	luax_catchexcept(L, [&](){ clone = t->clone(); });
 	luax_pushtype(L, "Source", AUDIO_SOURCE_T, clone);
 	return 1;
 }
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	EXCEPT_GUARD(t->setPosition(v);)
+	luax_catchexcept(L, [&](){ t->setPosition(v); });
 	return 0;
 }
 
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	EXCEPT_GUARD(t->getPosition(v);)
+	luax_catchexcept(L, [&](){ t->getPosition(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	EXCEPT_GUARD(t->setVelocity(v);)
+	luax_catchexcept(L, [&](){ t->setVelocity(v); });
 	return 0;
 }
 
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	EXCEPT_GUARD(t->getVelocity(v);)
+	luax_catchexcept(L, [&](){ t->getVelocity(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	EXCEPT_GUARD(t->setDirection(v);)
+	luax_catchexcept(L, [&](){ t->setDirection(v); });
 	return 0;
 }
 
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	EXCEPT_GUARD(t->getDirection(v);)
+	luax_catchexcept(L, [&](){ t->getDirection(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	float innerAngle = (float) luaL_checknumber(L, 2);
 	float outerAngle = (float) luaL_checknumber(L, 3);
 	float outerVolume = (float) luaL_optnumber(L, 4, 0.0);
-	EXCEPT_GUARD(t->setCone(innerAngle, outerAngle, outerVolume);)
+	luax_catchexcept(L, [&](){ t->setCone(innerAngle, outerAngle, outerVolume); });
 	return 0;
 }
 
 {
 	Source *t = luax_checksource(L, 1);
 	float innerAngle, outerAngle, outerVolume;
-	EXCEPT_GUARD(t->getCone(innerAngle, outerAngle, outerVolume);)
+	luax_catchexcept(L, [&](){ t->getCone(innerAngle, outerAngle, outerVolume); });
 	lua_pushnumber(L, innerAngle);
 	lua_pushnumber(L, outerAngle);
 	lua_pushnumber(L, outerVolume);
 int w_Source_setRelative(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	EXCEPT_GUARD(t->setRelative(luax_toboolean(L, 2));)
+	luax_catchexcept(L, [&](){ t->setRelative(luax_toboolean(L, 2)); });
 	return 0;
 }
 
 int w_Source_isRelative(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	EXCEPT_GUARD(luax_pushboolean(L, t->isRelative());)
+	luax_catchexcept(L, [&](){ luax_pushboolean(L, t->isRelative()); });
 	return 1;
 }
 
 	float dmax = (float)luaL_checknumber(L, 3);
 	if (dref < .0f || dmax < .0f)
 		return luaL_error(L, "Invalid distances: %f, %f. Must be > 0", dref, dmax);
-	EXCEPT_GUARD(t->setReferenceDistance(dref);)
-	EXCEPT_GUARD(t->setMaxDistance(dmax);)
+	luax_catchexcept(L, [&]() {
+		t->setReferenceDistance(dref);
+		t->setMaxDistance(dmax);
+	});
 	return 0;
 }
 
 int w_Source_getAttenuationDistances(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	EXCEPT_GUARD(lua_pushnumber(L, t->getReferenceDistance());)
-	EXCEPT_GUARD(lua_pushnumber(L, t->getMaxDistance());)
+	luax_catchexcept(L, [&]() {
+		lua_pushnumber(L, t->getReferenceDistance());
+		lua_pushnumber(L, t->getMaxDistance());
+	});
 	return 2;
 }
 
 	float rolloff = (float)luaL_checknumber(L, 2);
 	if (rolloff < .0f)
 		return luaL_error(L, "Invalid rolloff: %f. Must be > 0.", rolloff);
-	EXCEPT_GUARD(t->setRolloffFactor(rolloff);)
+	luax_catchexcept(L, [&](){ t->setRolloffFactor(rolloff); });
 	return 0;
 }
 
 int w_Source_getRolloff(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	EXCEPT_GUARD(lua_pushnumber(L, t->getRolloffFactor());)
+	luax_catchexcept(L, [&](){ lua_pushnumber(L, t->getRolloffFactor()); });
 	return 1;
 }
 

File src/modules/event/sdl/wrap_Event.cpp

 {
 	if (instance == 0)
 	{
-		EXCEPT_GUARD(instance = new Event();)
+		luax_catchexcept(L, [&](){ instance = new Event(); });
 	}
 	else
 		instance->retain();

File src/modules/filesystem/physfs/File.cpp

 {
 namespace filesystem
 {
+
+extern bool hack_setupWriteDirectory();
+
 namespace physfs
 {
 
-extern bool hack_setupWriteDirectory();
-
 File::File(const std::string &filename)
 	: filename(filename)
 	, file(0)

File src/modules/filesystem/physfs/wrap_File.cpp

-/**
- * Copyright (c) 2006-2014 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "wrap_File.h"
-
-#include "common/Data.h"
-#include "common/Exception.h"
-#include "common/int.h"
-
-namespace love
-{
-namespace filesystem
-{
-namespace physfs
-{
-
-int luax_ioError(lua_State *L, const char *fmt, ...)
-{
-	va_list args;
-	va_start(args, fmt);
-
-	lua_pushnil(L);
-	lua_pushvfstring(L, fmt, args);
-
-	va_end(args);
-	return 2;
-}
-
-File *luax_checkfile(lua_State *L, int idx)
-{
-	return luax_checktype<File>(L, idx, "File", FILESYSTEM_FILE_T);
-}
-
-int w_File_getSize(lua_State *L)
-{
-	File *t = luax_checkfile(L, 1);
-
-	int64 size = -1;
-	try
-	{
-		size = t->getSize();
-	}
-	catch (love::Exception &e)
-	{
-		return luax_ioError(L, "%s", e.what());
-	}
-
-	// Push nil on failure or if size does not fit into a double precision floating-point number.
-	if (size == -1)
-		return luax_ioError(L, "Could not determine file size.");
-	else if (size >= 0x20000000000000LL)
-		return luax_ioError(L, "Size is too large.");
-
-	lua_pushnumber(L, (lua_Number) size);
-	return 1;
-}
-
-int w_File_open(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	const char *str = luaL_checkstring(L, 2);
-	File::Mode mode;
-
-	if (!File::getConstant(str, mode))
-		return luaL_error(L, "Incorrect file open mode: %s", str);
-
-	try
-	{
-		luax_pushboolean(L, file->open(mode));
-	}
-	catch (love::Exception &e)
-	{
-		return luax_ioError(L, "%s", e.what());
-	}
-
-	return 1;
-}
-
-int w_File_close(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	luax_pushboolean(L, file->close());
-	return 1;
-}
-
-int w_File_isOpen(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	luax_pushboolean(L, file->isOpen());
-	return 1;
-}
-
-int w_File_read(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	Data *d = 0;
-
-	int64 size = (int64)luaL_optnumber(L, 2, File::ALL);
-
-	try
-	{
-		d = file->read(size);
-	}
-	catch (love::Exception &e)
-	{
-		return luax_ioError(L, "%s", e.what());
-	}
-
-	lua_pushlstring(L, (const char *) d->getData(), d->getSize());
-	lua_pushnumber(L, d->getSize());
-	d->release();
-	return 2;
-}
-
-int w_File_write(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	bool result = false;
-
-	if (lua_isstring(L, 2))
-	{
-		try
-		{
-			size_t datasize = 0;
-			const char *data = lua_tolstring(L, 2, &datasize);
-
-			if (!lua_isnoneornil(L, 3))
-				datasize = luaL_checkinteger(L, 3);
-
-			result = file->write(data, datasize);
-		}
-		catch (love::Exception &e)
-		{
-			return luax_ioError(L, "%s", e.what());
-		}
-	}
-	else if (luax_istype(L, 2, DATA_T))
-	{
-		try
-		{
-			love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T);
-			result = file->write(data, luaL_optinteger(L, 3, data->getSize()));
-		}
-		catch (love::Exception &e)
-		{
-			return luax_ioError(L, "%s", e.what());
-		}
-	}
-	else
-	{
-		return luaL_argerror(L, 2, "string or data expected");
-	}
-
-	luax_pushboolean(L, result);
-	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 luax_ioError(L, "%s", e.what());
-	}
-	luax_pushboolean(L, success);
-	return 1;
-}
-
-int w_File_eof(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	luax_pushboolean(L, file->eof());
-	return 1;
-}
-
-int w_File_tell(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	int64 pos = file->tell();
-	// Push nil on failure or if pos does not fit into a double precision floating-point number.
-	if (pos == -1)
-		return luax_ioError(L, "Invalid position.");
-	else if (pos >= 0x20000000000000LL)
-		return luax_ioError(L, "Number is too large.");
-	else
-		lua_pushnumber(L, (lua_Number)pos);
-	return 1;
-}
-
-int w_File_seek(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-	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;
-}
-
-int w_File_lines(lua_State *L)
-{
-	File *file = luax_checkfile(L, 1);
-
-	lua_pushnumber(L, 0); // File position.
-	luax_pushboolean(L, file->getMode() != File::CLOSED); // Save current file mode.
-
-	if (file->getMode() != File::READ)
-	{
-		if (file->getMode() != File::CLOSED)
-			file->close();
-
-		bool success = false;
-		EXCEPT_GUARD(success = file->open(File::READ);)
-
-		if (!success)
-			return luaL_error(L, "Could not open file.");
-	}
-
-	lua_pushcclosure(L, Filesystem::lines_i, 3);
-	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 luax_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 luax_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 luax_ioError(L, "Unknown file mode.");
-
-	lua_pushstring(L, str);
-	return 1;
-}
-
-static const luaL_Reg functions[] =
-{
-	{ "getSize", w_File_getSize },
-	{ "open", w_File_open },
-	{ "close", w_File_close },
-	{ "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 }
-};
-
-extern "C" int luaopen_file(lua_State *L)
-{
-	return luax_register_type(L, "File", functions);
-}
-
-} // physfs
-} // filesystem
-} // love

File src/modules/filesystem/physfs/wrap_File.h

-/**
- * Copyright (c) 2006-2014 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_H
-#define LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_H
-
-// LOVE
-#include "common/runtime.h"
-#include "Filesystem.h"
-#include "File.h"
-
-namespace love
-{
-namespace filesystem
-{
-namespace physfs
-{
-
-// Does not use lua_error, so it's safe to call in exception handling code.
-int luax_ioError(lua_State *L, const char *fmt, ...);
-
-File *luax_checkfile(lua_State *L, int idx);
-int w_File_getSize(lua_State *L);
-int w_File_open(lua_State *L);
-int w_File_close(lua_State *L);
-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
-} // filesystem
-} // love
-
-#endif // LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_H

File src/modules/filesystem/physfs/wrap_FileData.cpp

-/**
- * Copyright (c) 2006-2014 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "wrap_FileData.h"
-
-#include "common/wrap_Data.h"
-
-namespace love
-{
-namespace filesystem
-{
-namespace physfs
-{
-
-FileData *luax_checkfiledata(lua_State *L, int idx)
-{
-	return luax_checktype<FileData>(L, idx, "FileData", FILESYSTEM_FILE_DATA_T);
-}
-
-int w_FileData_getFilename(lua_State *L)
-{
-	FileData *t = luax_checkfiledata(L, 1);
-	lua_pushstring(L, t->getFilename().c_str());
-	return 1;
-}
-
-int w_FileData_getExtension(lua_State *L)
-{
-	FileData *t = luax_checkfiledata(L, 1);
-	lua_pushstring(L, t->getExtension().c_str());
-	return 1;
-}
-
-static const luaL_Reg w_FileData_functions[] =
-{
-	// Data
-	{ "getString", w_Data_getString },
-	{ "getPointer", w_Data_getPointer },
-	{ "getSize", w_Data_getSize },
-
-	{ "getFilename", w_FileData_getFilename },
-	{ "getExtension", w_FileData_getExtension },
-
-	{ 0, 0 }
-};
-
-extern "C" int luaopen_filedata(lua_State *L)
-{
-	return luax_register_type(L, "FileData", w_FileData_functions);
-}
-
-} // physfs
-} // filesystem
-} // love

File src/modules/filesystem/physfs/wrap_FileData.h

-/**
- * Copyright (c) 2006-2014 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_DATA_H
-#define LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_DATA_H
-
-// LOVE
-#include "common/runtime.h"
-
-#include "filesystem/FileData.h"
-
-namespace love
-{
-namespace filesystem
-{
-namespace physfs
-{
-
-FileData *luax_checkfiledata(lua_State *L, int idx);
-int w_FileData_getFilename(lua_State *L);
-int w_FileData_getExtension(lua_State *L);
-extern "C" int luaopen_filedata(lua_State *L);
-
-} // physfs
-} // filesystem
-} // love
-
-#endif // LOVE_FILESYSTEM_PHYSFS_WRAP_FILE_DATA_H

File src/modules/filesystem/wrap_File.cpp

+/**
+ * Copyright (c) 2006-2014 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_File.h"
+
+#include "physfs/Filesystem.h"
+
+#include "common/Data.h"
+#include "common/Exception.h"
+#include "common/int.h"
+
+namespace love
+{
+namespace filesystem
+{
+
+int luax_ioError(lua_State *L, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+
+	lua_pushnil(L);
+	lua_pushvfstring(L, fmt, args);
+
+	va_end(args);
+	return 2;
+}
+
+File *luax_checkfile(lua_State *L, int idx)
+{
+	return luax_checktype<File>(L, idx, "File", FILESYSTEM_FILE_T);
+}
+
+int w_File_getSize(lua_State *L)
+{
+	File *t = luax_checkfile(L, 1);
+
+	int64 size = -1;
+	try
+	{
+		size = t->getSize();
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	// Push nil on failure or if size does not fit into a double precision floating-point number.
+	if (size == -1)
+		return luax_ioError(L, "Could not determine file size.");
+	else if (size >= 0x20000000000000LL)
+		return luax_ioError(L, "Size is too large.");
+
+	lua_pushnumber(L, (lua_Number) size);
+	return 1;
+}
+
+int w_File_open(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	const char *str = luaL_checkstring(L, 2);
+	File::Mode mode;
+
+	if (!File::getConstant(str, mode))
+		return luaL_error(L, "Incorrect file open mode: %s", str);
+
+	try
+	{
+		luax_pushboolean(L, file->open(mode));
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	return 1;
+}
+
+int w_File_close(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	luax_pushboolean(L, file->close());
+	return 1;
+}
+
+int w_File_isOpen(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	luax_pushboolean(L, file->isOpen());
+	return 1;
+}
+
+int w_File_read(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	Data *d = 0;
+
+	int64 size = (int64)luaL_optnumber(L, 2, File::ALL);
+
+	try
+	{
+		d = file->read(size);
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	lua_pushlstring(L, (const char *) d->getData(), d->getSize());
+	lua_pushnumber(L, d->getSize());
+	d->release();
+	return 2;
+}
+
+int w_File_write(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	bool result = false;
+
+	if (lua_isstring(L, 2))
+	{
+		try
+		{
+			size_t datasize = 0;
+			const char *data = lua_tolstring(L, 2, &datasize);
+
+			if (!lua_isnoneornil(L, 3))
+				datasize = luaL_checkinteger(L, 3);
+
+			result = file->write(data, datasize);
+		}
+		catch (love::Exception &e)
+		{
+			return luax_ioError(L, "%s", e.what());
+		}
+	}
+	else if (luax_istype(L, 2, DATA_T))
+	{
+		try
+		{
+			love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T);
+			result = file->write(data, luaL_optinteger(L, 3, data->getSize()));
+		}
+		catch (love::Exception &e)
+		{
+			return luax_ioError(L, "%s", e.what());
+		}
+	}
+	else
+	{
+		return luaL_argerror(L, 2, "string or data expected");
+	}
+
+	luax_pushboolean(L, result);
+	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 luax_ioError(L, "%s", e.what());
+	}
+	luax_pushboolean(L, success);
+	return 1;
+}
+
+int w_File_eof(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	luax_pushboolean(L, file->eof());
+	return 1;
+}
+
+int w_File_tell(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	int64 pos = file->tell();
+	// Push nil on failure or if pos does not fit into a double precision floating-point number.
+	if (pos == -1)
+		return luax_ioError(L, "Invalid position.");
+	else if (pos >= 0x20000000000000LL)
+		return luax_ioError(L, "Number is too large.");
+	else
+		lua_pushnumber(L, (lua_Number)pos);
+	return 1;
+}
+
+int w_File_seek(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	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;
+}
+
+int w_File_lines(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+
+	lua_pushnumber(L, 0); // File position.
+	luax_pushboolean(L, file->getMode() != File::CLOSED); // Save current file mode.
+
+	if (file->getMode() != File::READ)
+	{
+		if (file->getMode() != File::CLOSED)
+			file->close();
+
+		bool success = false;
+		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
+
+		if (!success)
+			return luaL_error(L, "Could not open file.");
+	}
+
+	lua_pushcclosure(L, physfs::Filesystem::lines_i, 3);
+	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 luax_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 luax_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 luax_ioError(L, "Unknown file mode.");
+
+	lua_pushstring(L, str);
+	return 1;
+}
+
+static const luaL_Reg functions[] =
+{
+	{ "getSize", w_File_getSize },
+	{ "open", w_File_open },
+	{ "close", w_File_close },
+	{ "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 }
+};
+
+extern "C" int luaopen_file(lua_State *L)
+{
+	return luax_register_type(L, "File", functions);
+}
+
+} // filesystem
+} // love

File src/modules/filesystem/wrap_File.h

+/**
+ * Copyright (c) 2006-2014 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FILESYSTEM_WRAP_FILE_H
+#define LOVE_FILESYSTEM_WRAP_FILE_H
+
+// LOVE
+#include "common/runtime.h"
+#include "File.h"
+
+namespace love
+{
+namespace filesystem
+{
+
+// Does not use lua_error, so it's safe to call in exception handling code.
+int luax_ioError(lua_State *L, const char *fmt, ...);
+
+File *luax_checkfile(lua_State *L, int idx);
+int w_File_getSize(lua_State *L);
+int w_File_open(lua_State *L);
+int w_File_close(lua_State *L);
+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);
+
+} // filesystem
+} // love
+
+#endif // LOVE_FILESYSTEM_WRAP_FILE_H

File src/modules/filesystem/wrap_FileData.cpp

+/**
+ * Copyright (c) 2006-2014 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_FileData.h"
+
+#include "common/wrap_Data.h"
+
+namespace love
+{
+namespace filesystem
+{
+
+FileData *luax_checkfiledata(lua_State *L, int idx)
+{
+	return luax_checktype<FileData>(L, idx, "FileData", FILESYSTEM_FILE_DATA_T);
+}
+
+int w_FileData_getFilename(lua_State *L)
+{
+	FileData *t = luax_checkfiledata(L, 1);
+	lua_pushstring(L, t->getFilename().c_str());
+	return 1;
+}
+
+int w_FileData_getExtension(lua_State *L)
+{
+	FileData *t = luax_checkfiledata(L, 1);
+	lua_pushstring(L, t->getExtension().c_str());
+	return 1;
+}
+
+static const luaL_Reg w_FileData_functions[] =
+{
+	// Data
+	{ "getString", w_Data_getString },
+	{ "getPointer", w_Data_getPointer },
+	{ "getSize", w_Data_getSize },
+
+	{ "getFilename", w_FileData_getFilename },
+	{ "getExtension", w_FileData_getExtension },
+
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_filedata(lua_State *L)
+{
+	return luax_register_type(L, "FileData", w_FileData_functions);
+}
+
+} // filesystem
+} // love

File src/modules/filesystem/wrap_FileData.h

+/**
+ * Copyright (c) 2006-2014 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FILESYSTEM_WRAP_FILE_DATA_H
+#define LOVE_FILESYSTEM_WRAP_FILE_DATA_H
+
+// LOVE
+#include "common/runtime.h"
+#include "FileData.h"
+
+namespace love
+{
+namespace filesystem
+{
+
+FileData *luax_checkfiledata(lua_State *L, int idx);
+int w_FileData_getFilename(lua_State *L);
+int w_FileData_getExtension(lua_State *L);
+extern "C" int luaopen_filedata(lua_State *L);
+
+} // filesystem
+} // love
+
+#endif // LOVE_FILESYSTEM_WRAP_FILE_DATA_H

File src/modules/filesystem/wrap_Filesystem.cpp

+/**
+ * Copyright (c) 2006-2014 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "wrap_Filesystem.h"
+#include "wrap_File.h"
+#include "wrap_FileData.h"
+
+#include "physfs/Filesystem.h"
+
+// SDL
+#include <SDL_loadso.h>
+
+namespace love
+{
+namespace filesystem
+{
+
+static physfs::Filesystem *instance = 0;
+
+bool hack_setupWriteDirectory()
+{
+	if (instance != 0)
+		return instance->setupWriteDirectory();
+	return false;
+}
+
+int w_init(lua_State *L)
+{
+	const char *arg0 = luaL_checkstring(L, 1);
+	luax_catchexcept(L, [&](){ instance->init(arg0); });
+	return 0;
+}
+
+int w_setFused(lua_State *L)
+{
+	// no error checking needed, everything, even nothing
+	// can be converted to a boolean
+	instance->setFused(luax_toboolean(L, 1));
+	return 0;
+}
+
+int w_isFused(lua_State *L)
+{
+	luax_pushboolean(L, instance->isFused());
+	return 1;
+}
+
+int w_setIdentity(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	bool append = luax_optboolean(L, 2, false);
+
+	if (!instance->setIdentity(arg, append))
+		return luaL_error(L, "Could not set write directory.");
+
+	return 0;
+}
+
+int w_getIdentity(lua_State *L)
+{
+	lua_pushstring(L, instance->getIdentity());
+	return 1;
+}
+
+int w_setSource(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+
+	if (!instance->setSource(arg))
+		return luaL_error(L, "Could not set source.");
+
+	return 0;
+}
+
+int w_getSource(lua_State *L)
+{
+	lua_pushstring(L, instance->getSource());
+	return 1;
+}
+
+int w_mount(lua_State *L)
+{
+	const char *archive = luaL_checkstring(L, 1);
+	const char *mountpoint = luaL_checkstring(L, 2);
+	bool append = luax_optboolean(L, 3, false);
+
+	luax_pushboolean(L, instance->mount(archive, mountpoint, append));
+	return 1;
+}
+
+int w_unmount(lua_State *L)
+{
+	const char *archive = luaL_checkstring(L, 1);
+
+	luax_pushboolean(L, instance->unmount(archive));
+	return 1;
+}
+
+int w_newFile(lua_State *L)
+{
+	const char *filename = luaL_checkstring(L, 1);
+
+	const char *str = 0;
+	File::Mode mode = File::CLOSED;
+
+	if (lua_isstring(L, 2))
+	{
+		str = luaL_checkstring(L, 2);
+		if (!File::getConstant(str, mode))
+			return luaL_error(L, "Incorrect file open mode: %s", str);
+	}
+
+	File *t = instance->newFile(filename);
+
+	if (mode != File::CLOSED)
+	{
+		try
+		{
+			if (!t->open(mode))
+				throw love::Exception("Could not open file.");
+		}
+		catch (love::Exception &e)
+		{
+			t->release();
+			return luax_ioError(L, "%s", e.what());
+		}
+	}
+
+	luax_pushtype(L, "File", FILESYSTEM_FILE_T, t);
+	return 1;
+}
+
+FileData *luax_getfiledata(lua_State *L, int idx)
+{
+	FileData *data = nullptr;
+	File *file = nullptr;
+
+	if (lua_isstring(L, idx))
+	{
+		const char *filename = luaL_checkstring(L, idx);
+		file = instance->newFile(filename);
+	}
+	else if (luax_istype(L, idx, FILESYSTEM_FILE_T))
+	{
+		file = luax_checkfile(L, idx);
+		file->retain();
+	}
+	else if (luax_istype(L, idx, FILESYSTEM_FILE_DATA_T))
+	{
+		data = luax_checkfiledata(L, idx);
+		data->retain();
+	}
+
+	if (!data && !file)
+	{
+		luaL_argerror(L, idx, "filename, File, or FileData expected");
+		return nullptr; // Never reached.
+	}
+
+	if (file)
+	{
+		luax_catchexcept(L,
+			[&]() { data = file->read(); },
+			[&]() { file->release(); }
+		);
+	}
+
+	return data;
+}
+
+int w_newFileData(lua_State *L)
+{
+	// Single argument: treat as filepath or File.
+	if (lua_gettop(L) == 1)
+	{
+		// We don't use luax_getfiledata because we want to use an ioError.
+		if (lua_isstring(L, 1))
+			luax_convobj(L, 1, "filesystem", "newFile");
+
+		// Get FileData from the File.
+		if (luax_istype(L, 1, FILESYSTEM_FILE_T))
+		{
+			File *file = luax_checkfile(L, 1);
+
+			FileData *data = 0;
+			try
+			{
+				data = file->read();
+			}
+			catch (love::Exception &e)
+			{
+				return luax_ioError(L, "%s", e.what());
+			}
+			luax_pushtype(L, "FileData", FILESYSTEM_FILE_DATA_T, data);
+			return 1;
+		}
+		else
+			return luaL_argerror(L, 1, "filename or File expected");
+	}
+
+	size_t length = 0;
+	const char *str = luaL_checklstring(L, 1, &length);
+	const char *filename = luaL_checkstring(L, 2);
+	const char *decstr = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0;
+
+	FileData::Decoder decoder = FileData::FILE;
+
+	if (decstr && !FileData::getConstant(decstr, decoder))
+		return luaL_error(L, "Invalid FileData decoder: %s", decstr);
+
+	FileData *t = 0;
+
+	switch (decoder)
+	{
+	case FileData::FILE:
+		t = instance->newFileData((void *)str, (int)length, filename);
+		break;
+	case FileData::BASE64:
+		t = instance->newFileData(str, filename);
+		break;
+	default:
+		return luaL_error(L, "Invalid FileData decoder: %s", decstr);
+	}
+
+	luax_pushtype(L, "FileData", FILESYSTEM_FILE_DATA_T, t);
+	return 1;
+}
+
+int w_getWorkingDirectory(lua_State *L)
+{
+	lua_pushstring(L, instance->getWorkingDirectory());
+	return 1;
+}
+
+int w_getUserDirectory(lua_State *L)
+{
+	luax_pushstring(L, instance->getUserDirectory());
+	return 1;
+}
+
+int w_getAppdataDirectory(lua_State *L)
+{
+	luax_pushstring(L, instance->getAppdataDirectory());
+	return 1;
+}
+
+int w_getSaveDirectory(lua_State *L)
+{
+	lua_pushstring(L, instance->getSaveDirectory());
+	return 1;
+}
+
+int w_getSourceBaseDirectory(lua_State *L)
+{
+	luax_pushstring(L, instance->getSourceBaseDirectory());
+	return 1;
+}
+
+int w_isDirectory(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	luax_pushboolean(L, instance->isDirectory(arg));
+	return 1;
+}
+
+int w_isFile(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	luax_pushboolean(L, instance->isFile(arg));
+	return 1;
+}
+
+int w_createDirectory(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	luax_pushboolean(L, instance->createDirectory(arg));
+	return 1;
+}
+
+int w_remove(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	luax_pushboolean(L, instance->remove(arg));
+	return 1;
+}
+
+int w_read(lua_State *L)
+{
+	const char *filename = luaL_checkstring(L, 1);
+	int64 len = (int64) luaL_optinteger(L, 2, File::ALL);
+
+	Data *data = 0;
+	try
+	{
+		data = instance->read(filename, len);
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	if (data == 0)
+		return luax_ioError(L, "File could not be read.");
+
+	// Push the string.
+	lua_pushlstring(L, (const char *) data->getData(), data->getSize());
+
+	// Push the size.
+	lua_pushinteger(L, data->getSize());
+
+	// Lua has a copy now, so we can free it.
+	data->release();
+
+	return 2;
+}
+
+static int w_write_or_append(lua_State *L, File::Mode mode)
+{
+	const char *filename = luaL_checkstring(L, 1);
+
+	const char *input = 0;
+	size_t len = 0;
+
+	if (luax_istype(L, 2, DATA_T))
+	{
+		love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T);
+		input = (const char *) data->getData();
+		len = data->getSize();
+	}
+	else if (lua_isstring(L, 2))
+		input = lua_tolstring(L, 2, &len);
+	else
+		return luaL_argerror(L, 2, "string or Data expected");
+
+	// Get how much we should write. Length of string default.
+	len = luaL_optinteger(L, 3, len);
+
+	try
+	{
+		if (mode == File::APPEND)
+			instance->append(filename, (const void *) input, len);
+		else
+			instance->write(filename, (const void *) input, len);
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	luax_pushboolean(L, true);
+	return 1;
+}
+
+int w_write(lua_State *L)
+{
+	return w_write_or_append(L, File::WRITE);
+}
+
+int w_append(lua_State *L)
+{
+	return w_write_or_append(L, File::APPEND);
+}
+
+int w_getDirectoryItems(lua_State *L)
+{
+	return instance->getDirectoryItems(L);
+}
+
+int w_lines(lua_State *L)
+{
+	File *file;
+
+	if (lua_isstring(L, 1))
+	{
+		file = instance->newFile(lua_tostring(L, 1));
+		bool success = false;
+
+		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
+
+		if (!success)
+			return luaL_error(L, "Could not open file.");
+		
+		luax_pushtype(L, "File", FILESYSTEM_FILE_T, file);
+	}
+	else
+		return luaL_argerror(L, 1, "expected filename.");
+
+	lua_pushcclosure(L, physfs::Filesystem::lines_i, 1);
+	return 1;
+}
+
+int w_load(lua_State *L)
+{
+	std::string filename = std::string(luaL_checkstring(L, 1));
+
+	Data *data = 0;
+	try
+	{
+		data = instance->read(filename.c_str());
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	int status = luaL_loadbuffer(L, (const char *)data->getData(), data->getSize(), ("@" + filename).c_str());
+
+	data->release();
+
+	// Load the chunk, but don't run it.
+	switch (status)
+	{
+	case LUA_ERRMEM:
+		return luaL_error(L, "Memory allocation error: %s\n", lua_tostring(L, -1));
+	case LUA_ERRSYNTAX:
+		return luaL_error(L, "Syntax error: %s\n", lua_tostring(L, -1));
+	default: // success
+		return 1;
+	}
+}
+
+int w_getLastModified(lua_State *L)
+{
+	const char *filename = luaL_checkstring(L, 1);
+
+	int64 time = 0;
+	try
+	{
+		time = instance->getLastModified(filename);
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	lua_pushnumber(L, static_cast<lua_Number>(time));
+	return 1;
+}
+
+int w_getSize(lua_State *L)
+{
+	const char *filename = luaL_checkstring(L, 1);
+
+	int64 size = -1;
+	try
+	{
+		size = instance->getSize(filename);
+	}
+	catch (love::Exception &e)
+	{
+		return luax_ioError(L, "%s", e.what());
+	}
+
+	// Error on failure or if size does not fit into a double precision floating-point number.
+	if (size == -1)
+		return luax_ioError(L, "Could not determine file size.");
+	else if (size >= 0x20000000000000LL)
+		return luax_ioError(L, "Size too large to fit into a Lua number!");
+
+	lua_pushnumber(L, (lua_Number) size);
+	return 1;
+}
+
+int loader(lua_State *L)
+{
+	const char *filename = lua_tostring(L, -1);
+
+	std::string tmp(filename);
+	tmp += ".lua";
+
+	int size = tmp.size();
+
+	for (int i=0; i<size-4; i++)
+	{
+		if (tmp[i] == '.')
+		{
+			tmp[i] = '/';
+		}
+	}
+
+	// Check whether file exists.
+	if (instance->isFile(tmp.c_str()))
+	{
+		lua_pop(L, 1);
+		lua_pushstring(L, tmp.c_str());
+		// Ok, load it.
+		return w_load(L);
+	}
+
+	tmp = filename;
+	size = tmp.size();
+	for (int i=0; i<size; i++)
+	{
+		if (tmp[i] == '.')
+		{
+			tmp[i] = '/';
+		}