Browse Source

love.graphics.newImage, love.image.newImageData, etc. no longer leave Lua-owned FileData objects floating around waiting to be GC'd when called with filename arguments, resulting in less memory use on startup (resolves issue #890.)

Moved love.filesystem Lua wrapper code from src/modules/filesystem/physfs/ to src/modules/filesystem/.
Alex Szpakowski 11 years ago
parent
commit
724bdbd296

+ 6 - 6
CMakeLists.txt

@@ -185,6 +185,12 @@ set(LOVE_SRC_MODULE_FILESYSTEM_ROOT
 	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
@@ -192,12 +198,6 @@ 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

+ 6 - 6
platform/macosx/love-framework.xcodeproj/project.pbxproj

@@ -1554,12 +1554,6 @@
 				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>";
@@ -1736,6 +1730,12 @@
 				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>";

+ 14 - 0
src/common/runtime.h

@@ -489,6 +489,20 @@ Type luax_type(lua_State *L, int idx);
 		return luaL_error(L, "%s", lua_tostring(L, -1)); \
 }
 
+#define EXCEPT_GUARD_FINALLY(A, B) \
+{ \
+	bool should_error = false; \
+	try { A } \
+	catch (love::Exception &e) \
+	{ \
+		should_error = true; \
+		lua_pushstring(L, e.what()); \
+	} \
+	{ B } \
+	if (should_error) \
+		return luaL_error(L, "%s", lua_tostring(L, -1)); \
+}
+
 } // love
 
 #endif // LOVE_RUNTIME_H

+ 1 - 0
src/modules/audio/openal/Source.cpp

@@ -658,6 +658,7 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
 {
 	// Get more sound data.
 	int decoded = d->decode();
+	decoded = decoded >= 0 ? decoded : 0;
 
 	int fmt = getFormat(d->getChannels(), d->getBitDepth());
 

+ 1 - 4
src/modules/audio/wrap_Audio.cpp

@@ -41,10 +41,7 @@ int w_getSourceCount(lua_State *L)
 
 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;

+ 3 - 2
src/modules/filesystem/physfs/File.cpp

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

+ 3 - 4
src/modules/filesystem/physfs/wrap_File.cpp → src/modules/filesystem/wrap_File.cpp

@@ -20,6 +20,8 @@
 
 #include "wrap_File.h"
 
+#include "physfs/Filesystem.h"
+
 #include "common/Data.h"
 #include "common/Exception.h"
 #include "common/int.h"
@@ -28,8 +30,6 @@ namespace love
 {
 namespace filesystem
 {
-namespace physfs
-{
 
 int luax_ioError(lua_State *L, const char *fmt, ...)
 {
@@ -242,7 +242,7 @@ int w_File_lines(lua_State *L)
 			return luaL_error(L, "Could not open file.");
 	}
 
-	lua_pushcclosure(L, Filesystem::lines_i, 3);
+	lua_pushcclosure(L, physfs::Filesystem::lines_i, 3);
 	return 1;
 }
 
@@ -323,6 +323,5 @@ extern "C" int luaopen_file(lua_State *L)
 	return luax_register_type(L, "File", functions);
 }
 
-} // physfs
 } // filesystem
 } // love

+ 3 - 7
src/modules/filesystem/physfs/wrap_File.h → src/modules/filesystem/wrap_File.h

@@ -18,20 +18,17 @@
  * 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
+#ifndef LOVE_FILESYSTEM_WRAP_FILE_H
+#define LOVE_FILESYSTEM_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, ...);
@@ -53,8 +50,7 @@ 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
+#endif // LOVE_FILESYSTEM_WRAP_FILE_H

+ 0 - 3
src/modules/filesystem/physfs/wrap_FileData.cpp → src/modules/filesystem/wrap_FileData.cpp

@@ -26,8 +26,6 @@ namespace love
 {
 namespace filesystem
 {
-namespace physfs
-{
 
 FileData *luax_checkfiledata(lua_State *L, int idx)
 {
@@ -66,6 +64,5 @@ extern "C" int luaopen_filedata(lua_State *L)
 	return luax_register_type(L, "FileData", w_FileData_functions);
 }
 
-} // physfs
 } // filesystem
 } // love

+ 4 - 8
src/modules/filesystem/physfs/wrap_FileData.h → src/modules/filesystem/wrap_FileData.h

@@ -18,28 +18,24 @@
  * 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
+#ifndef LOVE_FILESYSTEM_WRAP_FILE_DATA_H
+#define LOVE_FILESYSTEM_WRAP_FILE_DATA_H
 
 // LOVE
 #include "common/runtime.h"
-
-#include "filesystem/FileData.h"
+#include "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
+#endif // LOVE_FILESYSTEM_WRAP_FILE_DATA_H

+ 82 - 26
src/modules/filesystem/physfs/wrap_Filesystem.cpp → src/modules/filesystem/wrap_Filesystem.cpp

@@ -20,6 +20,10 @@
 
 // LOVE
 #include "wrap_Filesystem.h"
+#include "wrap_File.h"
+#include "wrap_FileData.h"
+
+#include "physfs/Filesystem.h"
 
 // SDL
 #include <SDL_loadso.h>
@@ -28,10 +32,8 @@ namespace love
 {
 namespace filesystem
 {
-namespace physfs
-{
 
-static Filesystem *instance = 0;
+static physfs::Filesystem *instance = 0;
 
 bool hack_setupWriteDirectory()
 {
@@ -146,18 +148,73 @@ int w_newFile(lua_State *L)
 	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)
+	{
+		bool should_error = false;
+
+		// We don't use EXCEPT_GUARD_FINALLY because it returns int.
+		try
+		{
+			data = file->read();
+		}
+		catch (love::Exception &e)
+		{
+			should_error = true;
+			lua_pushstring(L, e.what());
+		}
+
+		file->release();
+
+		if (should_error)
+		{
+			luaL_error(L, "%s", lua_tostring(L, -1));
+			return nullptr; // Never reached.
+		}
+	}
+
+	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_checktype<File>(L, 1, "File", FILESYSTEM_FILE_T);
+			File *file = luax_checkfile(L, 1);
 
 			FileData *data = 0;
 			try
@@ -172,7 +229,7 @@ int w_newFileData(lua_State *L)
 			return 1;
 		}
 		else
-			return luaL_argerror(L, 1, "string or File expected");
+			return luaL_argerror(L, 1, "filename or File expected");
 	}
 
 	size_t length = 0;
@@ -369,7 +426,7 @@ int w_lines(lua_State *L)
 	else
 		return luaL_argerror(L, 1, "expected filename.");
 
-	lua_pushcclosure(L, Filesystem::lines_i, 1);
+	lua_pushcclosure(L, physfs::Filesystem::lines_i, 1);
 	return 1;
 }
 
@@ -576,32 +633,32 @@ int extloader(lua_State *L)
 // List of functions to wrap.
 static const luaL_Reg functions[] =
 {
-	{ "init",  w_init },
+	{ "init", w_init },
 	{ "setFused", w_setFused },
 	{ "isFused", w_isFused },
-	{ "setIdentity",  w_setIdentity },
+	{ "setIdentity", w_setIdentity },
 	{ "getIdentity", w_getIdentity },
-	{ "setSource",  w_setSource },
+	{ "setSource", w_setSource },
 	{ "getSource", w_getSource },
 	{ "mount", w_mount },
 	{ "unmount", w_unmount },
-	{ "newFile",  w_newFile },
-	{ "getWorkingDirectory",  w_getWorkingDirectory },
-	{ "getUserDirectory",  w_getUserDirectory },
-	{ "getAppdataDirectory",  w_getAppdataDirectory },
-	{ "getSaveDirectory",  w_getSaveDirectory },
+	{ "newFile", w_newFile },
+	{ "getWorkingDirectory", w_getWorkingDirectory },
+	{ "getUserDirectory", w_getUserDirectory },
+	{ "getAppdataDirectory", w_getAppdataDirectory },
+	{ "getSaveDirectory", w_getSaveDirectory },
 	{ "getSourceBaseDirectory", w_getSourceBaseDirectory },
-	{ "exists",  w_exists },
-	{ "isDirectory",  w_isDirectory },
-	{ "isFile",  w_isFile },
-	{ "createDirectory",  w_createDirectory },
-	{ "remove",  w_remove },
-	{ "read",  w_read },
-	{ "write",  w_write },
+	{ "exists", w_exists },
+	{ "isDirectory", w_isDirectory },
+	{ "isFile", w_isFile },
+	{ "createDirectory", w_createDirectory },
+	{ "remove", w_remove },
+	{ "read", w_read },
+	{ "write", w_write },
 	{ "append", w_append },
-	{ "getDirectoryItems",  w_getDirectoryItems },
-	{ "lines",  w_lines },
-	{ "load",  w_load },
+	{ "getDirectoryItems", w_getDirectoryItems },
+	{ "lines", w_lines },
+	{ "load", w_load },
 	{ "getLastModified", w_getLastModified },
 	{ "getSize", w_getSize },
 	{ "newFileData", w_newFileData },
@@ -619,7 +676,7 @@ extern "C" int luaopen_love_filesystem(lua_State *L)
 {
 	if (instance == 0)
 	{
-		EXCEPT_GUARD(instance = new Filesystem();)
+		EXCEPT_GUARD(instance = new physfs::Filesystem();)
 	}
 	else
 		instance->retain();
@@ -638,6 +695,5 @@ extern "C" int luaopen_love_filesystem(lua_State *L)
 	return luax_register_module(L, w);
 }
 
-} // physfs
 } // filesystem
 } // love

+ 14 - 9
src/modules/filesystem/physfs/wrap_Filesystem.h → src/modules/filesystem/wrap_Filesystem.h

@@ -18,20 +18,26 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_FILESYSTEM_PHYSFS_WRAP_FILESYSTEM_H
-#define LOVE_FILESYSTEM_PHYSFS_WRAP_FILESYSTEM_H
+#ifndef LOVE_FILESYSTEM_WRAP_FILESYSTEM_H
+#define LOVE_FILESYSTEM_WRAP_FILESYSTEM_H
 
 // LOVE
-#include "Filesystem.h"
-#include "wrap_File.h"
-#include "wrap_FileData.h"
+#include "common/runtime.h"
+#include "FileData.h"
 
 namespace love
 {
 namespace filesystem
 {
-namespace physfs
-{
+
+/**
+ * Gets FileData at the specified index. If the index contains a filepath or
+ * a File object, the FileData will be created from that.
+ * Note that this function retains the FileData object (possibly by creating it),
+ * so a matching release() is required!
+ * May trigger a Lua error.
+ **/
+FileData *luax_getFileData(lua_State *L, int idx);
 
 bool hack_setupWriteDirectory();
 int w_init(lua_State *L);
@@ -69,8 +75,7 @@ int loader(lua_State *L);
 int extloader(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_filesystem(lua_State *L);
 
-} // physfs
 } // filesystem
 } // love
 
-#endif // LOVE_FILESYSTEM_PHYSFS_WRAP_FILESYSTEM_H
+#endif // LOVE_FILESYSTEM_WRAP_FILESYSTEM_H

+ 20 - 25
src/modules/font/freetype/wrap_Font.cpp

@@ -25,6 +25,8 @@
 #include "font/wrap_GlyphData.h"
 #include "font/wrap_Rasterizer.h"
 
+#include "filesystem/wrap_Filesystem.h"
+
 #include "TrueTypeRasterizer.h"
 
 namespace love
@@ -34,31 +36,25 @@ namespace font
 namespace freetype
 {
 
-static Font *instance = 0;
+static Font *instance = nullptr;
 
 int w_newRasterizer(lua_State *L)
 {
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
-	Rasterizer *t = 0;
-
-	EXCEPT_GUARD(
-		if (luax_istype(L, 1, IMAGE_IMAGE_DATA_T))
-		{
-			love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
-			const char *g = luaL_checkstring(L, 2);
-			std::string glyphs(g);
-			t = instance->newRasterizer(d, glyphs);
-		}
-		else if (luax_istype(L, 1, DATA_T))
-		{
-			Data *d = luax_checkdata(L, 1);
-			int size = luaL_checkint(L, 2);
-			t = instance->newRasterizer(d, size);
-		}
-	)
+	Rasterizer *t = nullptr;
+
+	if (luax_istype(L, 1, IMAGE_IMAGE_DATA_T))
+	{
+		love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
+		const char *g = luaL_checkstring(L, 2);
+		std::string glyphs(g);
+		EXCEPT_GUARD(t = instance->newRasterizer(d, glyphs);)
+	}
+	else if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	{
+		love::filesystem::FileData *d = love::filesystem::luax_getFileData(L, 1);
+		int size = luaL_checkint(L, 2);
+		EXCEPT_GUARD_FINALLY(t = instance->newRasterizer(d, size);, d->release();)
+	}
 
 	luax_pushtype(L, "Rasterizer", FONT_RASTERIZER_T, t);
 	return 1;
@@ -67,13 +63,12 @@ int w_newRasterizer(lua_State *L)
 int w_newGlyphData(lua_State *L)
 {
 	Rasterizer *r = luax_checkrasterizer(L, 1);
-	GlyphData *t = 0;
+	GlyphData *t = nullptr;
 
 	// newGlyphData accepts a unicode character or a codepoint number.
 	if (lua_type(L, 2) == LUA_TSTRING)
 	{
 		std::string glyph = luax_checkstring(L, 2);
-
 		EXCEPT_GUARD(t = instance->newGlyphData(r, glyph);)
 	}
 	else
@@ -103,7 +98,7 @@ static const lua_CFunction types[] =
 
 extern "C" int luaopen_love_font(lua_State *L)
 {
-	if (instance == 0)
+	if (instance == nullptr)
 	{
 		EXCEPT_GUARD(instance = new Font();)
 	}

+ 35 - 27
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -22,7 +22,9 @@
 #include "OpenGL.h"
 #include "graphics/Texture.h"
 #include "image/ImageData.h"
+#include "image/Image.h"
 #include "font/Rasterizer.h"
+#include "filesystem/wrap_Filesystem.h"
 
 #include "scripts/graphics.lua.h"
 #include <cassert>
@@ -161,42 +163,52 @@ int w_newImage(lua_State *L)
 	if (fstr != nullptr && !Image::getConstant(fstr, format))
 		return luaL_error(L, "Invalid Image format: %s", fstr);
 
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
+	bool releasedata = false;
 
-	// Convert to ImageData/CompressedData, if necessary.
-	if (luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	// Convert to ImageData / CompressedData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	{
-		// Determine whether to convert to ImageData or CompressedData.
-		luax_getfunction(L, "image", "isCompressed");
-		lua_pushvalue(L, 1);
-		lua_call(L, 1, 1);
+		love::image::Image *image = (love::image::Image *) Module::findInstance("love.image.");
+		if (image == nullptr)
+			return luaL_error(L, "Cannot load images without the love.image module.");
 
-		bool compressed = luax_toboolean(L, -1);
-		lua_pop(L, 1);
+		love::filesystem::FileData *fdata = love::filesystem::luax_getFileData(L, 1);
 
-		if (compressed)
-			luax_convobj(L, 1, "image", "newCompressedData");
+		if (image->isCompressed(fdata))
+		{
+			EXCEPT_GUARD_FINALLY(cdata = image->newCompressedData(fdata);, fdata->release();)
+		}
 		else
-			luax_convobj(L, 1, "image", "newImageData");
-	}
+		{
+			EXCEPT_GUARD_FINALLY(data = image->newImageData(fdata);, fdata->release();)
+		}
 
-	if (luax_istype(L, 1, IMAGE_COMPRESSED_DATA_T))
+		// Lua's GC won't release the image data, so we should do it ourselves.
+		releasedata = true;
+	}
+	else if (luax_istype(L, 1, IMAGE_COMPRESSED_DATA_T))
 		cdata = luax_checktype<love::image::CompressedData>(L, 1, "CompressedData", IMAGE_COMPRESSED_DATA_T);
 	else
 		data = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
 
 	if (!data && !cdata)
-		return luaL_error(L, "Error creating image.");
+		return luaL_error(L, "Error creating image (could not load data.)");
 
 	// Create the image.
 	Image *image = nullptr;
-	EXCEPT_GUARD(
-		if (cdata)
-			image = instance->newImage(cdata, format);
-		else if (data)
-			image = instance->newImage(data, format);
+	EXCEPT_GUARD_FINALLY(
+		{
+			if (cdata)
+				image = instance->newImage(cdata, format);
+			else if (data)
+				image = instance->newImage(data, format);
+		},
+		{
+			if (releasedata && data)
+				data->release();
+			else if (releasedata && cdata)
+				cdata->release();
+		}
 	)
 
 	if (image == nullptr)
@@ -225,12 +237,8 @@ int w_newQuad(lua_State *L)
 
 int w_newFont(lua_State *L)
 {
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
 	// Convert to Rasterizer, if necessary.
-	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))
 	{
 		int idxs[] = {1, 2};
 		luax_convobj(L, idxs, 2, "font", "newRasterizer");

+ 4 - 16
src/modules/graphics/opengl/wrap_Shader.cpp

@@ -232,22 +232,10 @@ int w_Shader_sendMatrix(lua_State *L)
 		lua_pop(L, 1 + dimension);
 	}
 
-	bool should_error = false;
-
-	try
-	{
-		shader->sendMatrix(name, dimension, values, count);
-	}
-	catch(love::Exception &e)
-	{
-		should_error = true;
-		lua_pushstring(L, e.what());
-	}
-
-	delete[] values;
-
-	if (should_error)
-		return luaL_error(L, "%s", lua_tostring(L, -1));
+	EXCEPT_GUARD_FINALLY(
+		{ shader->sendMatrix(name, dimension, values, count); },
+		{ delete[] values; }
+	)
 
 	return 0;
 }

+ 14 - 26
src/modules/image/wrap_Image.cpp

@@ -25,12 +25,14 @@
 
 #include "magpie/Image.h"
 
+#include "filesystem/wrap_Filesystem.h"
+
 namespace love
 {
 namespace image
 {
 
-static Image *instance = 0;
+static Image *instance = nullptr;
 
 int w_newImageData(lua_State *L)
 {
@@ -42,7 +44,7 @@ int w_newImageData(lua_State *L)
 		if (w <= 0 || h <= 0)
 			return luaL_error(L, "Invalid image size.");
 
-		ImageData *t = 0;
+		ImageData *t = nullptr;
 		EXCEPT_GUARD(t = instance->newImageData(w, h);)
 
 		luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, t);
@@ -50,15 +52,10 @@ int w_newImageData(lua_State *L)
 	}
 
 	// Case 2: File(Data).
+	love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
 
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
-	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
-
-	ImageData *t = 0;
-	EXCEPT_GUARD(t = instance->newImageData(data);)
+	ImageData *t = nullptr;
+	EXCEPT_GUARD_FINALLY(t = instance->newImageData(data);, data->release();)
 
 	luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, t);
 	return 1;
@@ -66,14 +63,10 @@ int w_newImageData(lua_State *L)
 
 int w_newCompressedData(lua_State *L)
 {
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
+	love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
 
-	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
-
-	CompressedData *t = 0;
-	EXCEPT_GUARD(t = instance->newCompressedData(data);)
+	CompressedData *t = nullptr;
+	EXCEPT_GUARD_FINALLY(t = instance->newCompressedData(data);, data->release();)
 
 	luax_pushtype(L, "CompressedData", IMAGE_COMPRESSED_DATA_T, t);
 	return 1;
@@ -81,14 +74,9 @@ int w_newCompressedData(lua_State *L)
 
 int w_isCompressed(lua_State *L)
 {
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
-	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
-
-	bool compressed = false;
-	EXCEPT_GUARD(compressed = instance->isCompressed(data);)
+	love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
+	bool compressed = instance->isCompressed(data);
+	data->release();
 
 	luax_pushboolean(L, compressed);
 	return 1;
@@ -112,7 +100,7 @@ static const lua_CFunction types[] =
 
 extern "C" int luaopen_love_image(lua_State *L)
 {
-	if (instance == 0)
+	if (instance == nullptr)
 	{
 		EXCEPT_GUARD(instance = new love::image::magpie::Image();)
 	}

+ 6 - 9
src/modules/sound/wrap_Sound.cpp

@@ -20,6 +20,8 @@
 
 #include "wrap_Sound.h"
 
+#include "filesystem/wrap_Filesystem.h"
+
 // Implementations.
 #include "lullaby/Sound.h"
 
@@ -62,18 +64,13 @@ int w_newSoundData(lua_State *L)
 
 int w_newDecoder(lua_State *L)
 {
-	// Convert to FileData, if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "filesystem", "newFileData");
-
-	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
-
+	love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
 	int bufferSize = luaL_optint(L, 2, Decoder::DEFAULT_BUFFER_SIZE);
 
-	Decoder *t = 0;
-	EXCEPT_GUARD(t = instance->newDecoder(data, bufferSize);)
+	Decoder *t = nullptr;
+	EXCEPT_GUARD_FINALLY(t = instance->newDecoder(data, bufferSize);, data->release();)
 
-	if (t == 0)
+	if (t == nullptr)
 		return luaL_error(L, "Extension \"%s\" not supported.", data->getExtension().c_str());
 
 	luax_pushtype(L, "Decoder", SOUND_DECODER_T, t);