Browse Source

Error when invalid setting names are used in the tables passed to love.graphics.newCanvas and newImage. See issue #1312.

Alex Szpakowski 7 years ago
parent
commit
dd59803ad3

+ 22 - 0
src/common/runtime.h

@@ -474,6 +474,28 @@ extern "C" { // Also called from luasocket
 int luax_enumerror(lua_State *L, const char *enumName, const char *value);
 int luax_enumerror(lua_State *L, const char *enumName, const std::vector<std::string> &values, const char *value);
 
+template <typename T>
+void luax_checktablefields(lua_State *L, int idx, const char *enumName, bool (*getConstant)(const char *, T &))
+{
+	luaL_checktype(L, idx, LUA_TTABLE);
+
+	// We want to error for invalid / misspelled fields in the table.
+	lua_pushnil(L);
+	while (lua_next(L, idx))
+	{
+		if (lua_type(L, -2) != LUA_TSTRING)
+			luax_typerror(L, -2, "string");
+
+		const char *key = luaL_checkstring(L, -2);
+		T constantvalue;
+
+		if (!getConstant(key, constantvalue))
+			luax_enumerror(L, enumName, key);
+
+		lua_pop(L, 1);
+	}
+}
+
 /**
  * Calls luax_objlen/lua_rawlen depending on version
  **/

+ 36 - 0
src/modules/graphics/Canvas.cpp

@@ -195,6 +195,28 @@ std::vector<std::string> Canvas::getConstants(MipmapMode)
 	return mipmapModes.getNames();
 }
 
+bool Canvas::getConstant(const char *in, SettingType &out)
+{
+	return settingTypes.find(in, out);
+}
+
+bool Canvas::getConstant(SettingType in, const char *&out)
+{
+	return settingTypes.find(in, out);
+}
+
+const char *Canvas::getConstant(SettingType in)
+{
+	const char *name = nullptr;
+	getConstant(in, name);
+	return name;
+}
+
+std::vector<std::string> Canvas::getConstants(SettingType)
+{
+	return settingTypes.getNames();
+}
+
 StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
 {
 	{ "none",   MIPMAPS_NONE   },
@@ -204,6 +226,20 @@ StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEnt
 
 StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
 
+StringMap<Canvas::SettingType, Canvas::SETTING_MAX_ENUM>::Entry Canvas::settingTypeEntries[] =
+{
+	// Width / height / layers are currently omittted because they're separate
+	// arguments to newCanvas in the wrapper code.
+	{ "mipmaps",  SETTING_MIPMAPS   },
+	{ "format",   SETTING_FORMAT    },
+	{ "type",     SETTING_TYPE      },
+	{ "dpiscale", SETTING_DPI_SCALE },
+	{ "msaa",     SETTING_MSAA      },
+	{ "readable", SETTING_READABLE  },
+};
+
+StringMap<Canvas::SettingType, Canvas::SETTING_MAX_ENUM> Canvas::settingTypes(Canvas::settingTypeEntries, sizeof(Canvas::settingTypeEntries));
+
 } // graphics
 } // love
 

+ 22 - 0
src/modules/graphics/Canvas.h

@@ -47,6 +47,20 @@ public:
 		MIPMAPS_MAX_ENUM
 	};
 
+	enum SettingType
+	{
+		SETTING_WIDTH,
+		SETTING_HEIGHT,
+		SETTING_LAYERS,
+		SETTING_MIPMAPS,
+		SETTING_FORMAT,
+		SETTING_TYPE,
+		SETTING_DPI_SCALE,
+		SETTING_MSAA,
+		SETTING_READABLE,
+		SETTING_MAX_ENUM
+	};
+
 	struct Settings
 	{
 		int width  = 1;
@@ -81,6 +95,11 @@ public:
 	static bool getConstant(MipmapMode in, const char *&out);
 	static std::vector<std::string> getConstants(MipmapMode);
 
+	static bool getConstant(const char *in, SettingType &out);
+	static bool getConstant(SettingType in, const char *&out);
+	static const char *getConstant(SettingType in);
+	static std::vector<std::string> getConstants(SettingType);
+
 protected:
 
 	Settings settings;
@@ -89,6 +108,9 @@ private:
 
 	static StringMap<MipmapMode, MIPMAPS_MAX_ENUM>::Entry mipmapEntries[];
 	static StringMap<MipmapMode, MIPMAPS_MAX_ENUM> mipmapModes;
+
+	static StringMap<SettingType, SETTING_MAX_ENUM>::Entry settingTypeEntries[];
+	static StringMap<SettingType, SETTING_MAX_ENUM> settingTypes;
 	
 }; // Canvas
 

+ 3 - 0
src/modules/graphics/Graphics.cpp

@@ -129,6 +129,9 @@ Graphics::Graphics()
 	pixelScaleStack.reserve(16);
 	pixelScaleStack.push_back(1);
 
+	states.reserve(10);
+	states.push_back(DisplayState());
+
 	if (!Shader::initialize())
 		throw love::Exception("Shader support failed to initialize!");
 }

+ 31 - 0
src/modules/graphics/Image.cpp

@@ -340,5 +340,36 @@ Image::MipmapsType Image::Slices::validate() const
 		return MIPMAPS_NONE;
 }
 
+bool Image::getConstant(const char *in, SettingType &out)
+{
+	return settingTypes.find(in, out);
+}
+
+bool Image::getConstant(SettingType in, const char *&out)
+{
+	return settingTypes.find(in, out);
+}
+
+const char *Image::getConstant(SettingType in)
+{
+	const char *name = nullptr;
+	getConstant(in, name);
+	return name;
+}
+
+std::vector<std::string> Image::getConstants(SettingType)
+{
+	return settingTypes.getNames();
+}
+
+StringMap<Image::SettingType, Image::SETTING_MAX_ENUM>::Entry Image::settingTypeEntries[] =
+{
+	{ "mipmaps",  SETTING_MIPMAPS   },
+	{ "linear",   SETTING_LINEAR    },
+	{ "dpiscale", SETTING_DPI_SCALE },
+};
+
+StringMap<Image::SettingType, Image::SETTING_MAX_ENUM> Image::settingTypes(Image::settingTypeEntries, sizeof(Image::settingTypeEntries));
+
 } // graphics
 } // love

+ 16 - 0
src/modules/graphics/Image.h

@@ -46,6 +46,14 @@ public:
 		MIPMAPS_GENERATED,
 	};
 
+	enum SettingType
+	{
+		SETTING_MIPMAPS,
+		SETTING_LINEAR,
+		SETTING_DPI_SCALE,
+		SETTING_MAX_ENUM
+	};
+
 	struct Settings
 	{
 		bool mipmaps = false;
@@ -94,6 +102,11 @@ public:
 
 	static int imageCount;
 
+	static bool getConstant(const char *in, SettingType &out);
+	static bool getConstant(SettingType in, const char *&out);
+	static const char *getConstant(SettingType in);
+	static std::vector<std::string> getConstants(SettingType);
+
 protected:
 
 	Image(const Slices &data, const Settings &settings);
@@ -122,6 +135,9 @@ private:
 
 	void init(PixelFormat fmt, int w, int h, const Settings &settings);
 
+	static StringMap<SettingType, SETTING_MAX_ENUM>::Entry settingTypeEntries[];
+	static StringMap<SettingType, SETTING_MAX_ENUM> settingTypes;
+
 }; // Image
 
 } // graphics

+ 0 - 3
src/modules/graphics/opengl/Graphics.cpp

@@ -60,9 +60,6 @@ Graphics::Graphics()
 {
 	gl = OpenGL();
 
-	states.reserve(10);
-	states.push_back(DisplayState());
-
 	auto window = getInstance<love::window::Window>(M_WINDOW);
 
 	if (window != nullptr)

+ 12 - 11
src/modules/graphics/wrap_Graphics.cpp

@@ -701,10 +701,11 @@ static Image::Settings w__optImageSettings(lua_State *L, int idx, const Image::S
 
 	if (!lua_isnoneornil(L, idx))
 	{
-		luaL_checktype(L, idx, LUA_TTABLE);
-		settings.mipmaps = luax_boolflag(L, idx, "mipmaps", s.mipmaps);
-		settings.linear = luax_boolflag(L, idx, "linear", s.linear);
-		settings.dpiScale = (float) luax_numberflag(L, idx, "dpiscale", s.dpiScale);
+		luax_checktablefields<Image::SettingType>(L, idx, "image setting name", Image::getConstant);
+
+		settings.mipmaps = luax_boolflag(L, idx, Image::getConstant(Image::SETTING_MIPMAPS), s.mipmaps);
+		settings.linear = luax_boolflag(L, idx, Image::getConstant(Image::SETTING_LINEAR), s.linear);
+		settings.dpiScale = (float) luax_numberflag(L, idx, Image::getConstant(Image::SETTING_DPI_SCALE), s.dpiScale);
 	}
 
 	return settings;
@@ -1186,12 +1187,12 @@ int w_newCanvas(lua_State *L)
 
 	if (!lua_isnoneornil(L, startidx))
 	{
-		luaL_checktype(L, startidx, LUA_TTABLE);
+		luax_checktablefields<Canvas::SettingType>(L, startidx, "canvas setting name", Canvas::getConstant);
 
-		settings.dpiScale = (float) luax_numberflag(L, startidx, "dpiscale", settings.dpiScale);
-		settings.msaa = luax_intflag(L, startidx, "msaa", settings.msaa);
+		settings.dpiScale = (float) luax_numberflag(L, startidx, Canvas::getConstant(Canvas::SETTING_DPI_SCALE), settings.dpiScale);
+		settings.msaa = luax_intflag(L, startidx, Canvas::getConstant(Canvas::SETTING_MSAA), settings.msaa);
 
-		lua_getfield(L, startidx, "format");
+		lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_FORMAT));
 		if (!lua_isnoneornil(L, -1))
 		{
 			const char *str = luaL_checkstring(L, -1);
@@ -1200,7 +1201,7 @@ int w_newCanvas(lua_State *L)
 		}
 		lua_pop(L, 1);
 
-		lua_getfield(L, startidx, "type");
+		lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_TYPE));
 		if (!lua_isnoneornil(L, -1))
 		{
 			const char *str = luaL_checkstring(L, -1);
@@ -1209,7 +1210,7 @@ int w_newCanvas(lua_State *L)
 		}
 		lua_pop(L, 1);
 
-		lua_getfield(L, startidx, "readable");
+		lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_READABLE));
 		if (!lua_isnoneornil(L, -1))
 		{
 			settings.readable.hasValue = true;
@@ -1217,7 +1218,7 @@ int w_newCanvas(lua_State *L)
 		}
 		lua_pop(L, 1);
 
-		lua_getfield(L, startidx, "mipmaps");
+		lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_MIPMAPS));
 		if (!lua_isnoneornil(L, -1))
 		{
 			const char *str = luaL_checkstring(L, -1);

+ 1 - 17
src/modules/window/wrap_Window.cpp

@@ -54,23 +54,7 @@ static const char *settingName(Window::Setting setting)
 
 static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings)
 {
-	luaL_checktype(L, idx, LUA_TTABLE);
-
-	// We want to error for invalid / misspelled window attributes.
-	lua_pushnil(L);
-	while (lua_next(L, idx))
-	{
-		if (lua_type(L, -2) != LUA_TSTRING)
-			return luax_typerror(L, -2, "string");
-
-		const char *key = luaL_checkstring(L, -2);
-		Window::Setting setting;
-
-		if (!Window::getConstant(key, setting))
-			return luax_enumerror(L, "window setting", key);
-
-		lua_pop(L, 1);
-	}
+	luax_checktablefields<Window::Setting>(L, idx, "window setting", Window::getConstant);
 
 	lua_getfield(L, idx, settingName(Window::SETTING_FULLSCREEN_TYPE));
 	if (!lua_isnoneornil(L, -1))