diff options
Diffstat (limited to 'Sluift/ElementConvertors/DOMElementConvertor.cpp')
| -rw-r--r-- | Sluift/ElementConvertors/DOMElementConvertor.cpp | 201 | 
1 files changed, 201 insertions, 0 deletions
| diff --git a/Sluift/ElementConvertors/DOMElementConvertor.cpp b/Sluift/ElementConvertors/DOMElementConvertor.cpp new file mode 100644 index 0000000..784fcfd --- /dev/null +++ b/Sluift/ElementConvertors/DOMElementConvertor.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/DOMElementConvertor.h> + +#include <iostream> +#include <boost/smart_ptr/make_shared.hpp> +#include <lua.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/LuaUtils.h> +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Parser/AttributeMap.h> +#include <Swiften/Parser/Attribute.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Sluift/Lua/Debug.h> + +using namespace Swift; + +namespace { +	class ParserClient : public XMLParserClient { +		public: +			ParserClient(lua_State* L) : L(L), currentIndex(1) { +			} + +			virtual void handleStartElement( +					const std::string& element, const std::string& ns,  +					const AttributeMap& attributes) SWIFTEN_OVERRIDE { +				lua_checkstack(L, 6); +				lua_pushnumber(L, currentIndex); +				lua_newtable(L); +				lua_pushstring(L, element.c_str()); +				lua_setfield(L, -2, "tag"); +				if (!ns.empty()) { +					lua_pushstring(L, ns.c_str()); +					lua_setfield(L, -2, "ns"); +				} +				if (!attributes.getEntries().empty()) { +					lua_newtable(L); +					int i = 1; +					foreach(const AttributeMap::Entry& entry, attributes.getEntries()) { +						lua_pushnumber(L, i); +						lua_newtable(L); +						lua_pushstring(L, entry.getAttribute().getName().c_str()); +						lua_setfield(L, -2, "name"); +						if (!entry.getAttribute().getNamespace().empty()) { +							lua_pushstring(L, entry.getAttribute().getNamespace().c_str()); +							lua_setfield(L, -2, "ns"); +						} +						lua_pushstring(L, entry.getValue().c_str()); +						lua_setfield(L, -2, "value"); +						lua_settable(L, -3); +						++i; +					} +					lua_setfield(L, -2, "attributes"); +				} + +				indexStack.push_back(currentIndex); +				currentIndex = 1; +				lua_newtable(L); +			} + +			virtual void handleEndElement( +					const std::string&, const std::string&) SWIFTEN_OVERRIDE { +				lua_setfield(L, -2, "children"); +				lua_settable(L, -3); +				currentIndex = indexStack.back(); +				indexStack.pop_back(); +				currentIndex++; +			} + +			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE { +				lua_checkstack(L, 2); +				lua_pushnumber(L, currentIndex); +				lua_pushstring(L, data.c_str()); +				lua_settable(L, -3); +				currentIndex++; +			} + +		private: +			lua_State* L; +			std::vector<int> indexStack; +			int currentIndex; +	}; + +	std::string serializeElement(lua_State* L) { +		std::string tag; +		lua_getfield(L, -1, "tag"); +		if (lua_isstring(L, -1)) { +			tag = lua_tostring(L, -1); +		} +		lua_pop(L, 1); + +		std::string ns; +		lua_getfield(L, -1, "ns"); +		if (lua_isstring(L, -1)) { +			ns = lua_tostring(L, -1); +		} +		lua_pop(L, 1); + +		XMLElement element(tag, ns); + +		lua_getfield(L, -1, "attributes"); +		if (lua_istable(L, -1)) { +			int index = Lua::absoluteOffset(L, -1); +			for (lua_pushnil(L); lua_next(L, index) != 0; ) { +				if (lua_istable(L, -1)) { +					std::string attributeName; +					lua_getfield(L, -1, "name"); +					if (lua_isstring(L, -1)) { +						attributeName = lua_tostring(L, -1); +					} +					lua_pop(L, 1); + +					std::string attributeValue; +					lua_getfield(L, -1, "value"); +					if (lua_isstring(L, -1)) { +						attributeValue = lua_tostring(L, -1); +					} +					lua_pop(L, 1); + +					if (!attributeName.empty()) { +						element.setAttribute(attributeName, attributeValue); +					} +				} +				lua_pop(L, 1); // value +			} +		} +		lua_pop(L, 1); // children + +		lua_getfield(L, -1, "children"); +		if (lua_istable(L, -1)) { +			int index = Lua::absoluteOffset(L, -1); +			for (lua_pushnil(L); lua_next(L, index) != 0; ) { +				if (lua_isstring(L, -1)) { +					element.addNode(boost::make_shared<XMLTextNode>(lua_tostring(L, -1))); +				} +				else if (lua_istable(L, -1)) { +					element.addNode(boost::make_shared<XMLRawTextNode>(serializeElement(L))); +				} +				lua_pop(L, 1); // value +			} +		} +		lua_pop(L, 1); // children + +		return element.serialize(); +	} +} + +DOMElementConvertor::DOMElementConvertor() { +} + +DOMElementConvertor::~DOMElementConvertor() { +} + +boost::shared_ptr<Element> DOMElementConvertor::convertFromLua(lua_State* L, int index, const std::string& type) { +	if (!lua_istable(L, index) || type != "dom") { +		return boost::shared_ptr<Payload>(); +	} +	return boost::make_shared<RawXMLPayload>(serializeElement(L).c_str()); +} + +boost::optional<std::string> DOMElementConvertor::convertToLua( +		lua_State* L, boost::shared_ptr<Element> element) { +	// Serialize payload to XML +	boost::shared_ptr<Payload> payload = boost::dynamic_pointer_cast<Payload>(element); +	if (!payload) { +		return boost::optional<std::string>(); +	} + +	PayloadSerializer* serializer = serializers.getPayloadSerializer(payload); +	assert(serializer); +	std::string serializedPayload = serializer->serialize(payload); + +	lua_newtable(L); + +	// Parse the payload again +	ParserClient parserClient(L); +	boost::shared_ptr<XMLParser> parser(parsers.createXMLParser(&parserClient)); +	bool result = parser->parse(serializedPayload); +	assert(result); + +	// There can only be one element, so stripping the list +	lua_pushnil(L); +	lua_next(L, -2); +	Lua::registerTableToString(L, -1); + +	lua_replace(L, -3); +	lua_settop(L, -2); + +	return std::string("dom"); +} | 
 Swift
 Swift